Architecture & Tech stack
Tech stack
| Layer | Technology |
|---|---|
| Framework | React 18 + TypeScript 4.9 |
| Build | Create React App 5 + CRACO 7 |
| Routing | react-router-dom v6 (BrowserRouter) |
| Styling | Tailwind CSS 3 + CSS variables (design tokens) |
| HTTP | Axios 1.3 |
| Forms | react-hook-form 7 |
| Toast | react-hot-toast |
| Icons | lucide-react |
| CAPTCHA | @marsidev/react-turnstile (Cloudflare Turnstile) |
| QR Code | qrcode |
| Monorepo | @kioskgaming/ui, @kioskgaming/page-loading |
Not included: Redux, Zustand, React Query, Capacitor.
Directory structure
kioskgaming_agent/
├── src/
│ ├── index.tsx # Entry point, Service Worker registration
│ ├── App.tsx # Router + AuthProvider
│ ├── index.css # Tailwind + CSS variables
│ ├── config/env.ts # Centralized environment variables
│ ├── constants/index.ts # API URL, storage keys, custom events
│ ├── types/index.ts # TypeScript interfaces
│ ├── services/api.ts # HTTP client + all API functions
│ ├── hooks/ # useAuth, ledger hooks, zerox methods
│ ├── pages/ # Route pages
│ ├── components/
│ │ ├── auth/ # Login, forgot password, ProtectedRoute
│ │ ├── layout/ # AppLayout, AgentPageLayout
│ │ ├── credits/ # Buy credits, distribute, withdraw from shop
│ │ ├── dashboard/ # AgentHierarchyMiniTree
│ │ ├── finance/ # Withdrawal limits panel
│ │ ├── players/ # AgentPlayerDetailPanel
│ │ ├── shops/ # ShopGovernanceModal, status badge
│ │ └── ui/ # PortalEmptyState
│ └── utils/ # format, ledger, sanitize helpers
├── public/
│ ├── _redirects # Netlify / Cloudflare Pages
│ ├── .htaccess # Apache SPA fallback
│ └── web.config # IIS / Azure Static Web Apps
├── craco.config.js
├── tailwind.config.js
└── package.json
Entry points
| File | Role |
|---|---|
src/index.tsx | Mount React, register Service Worker (production only) |
src/App.tsx | Define routes, wrap AuthProvider |
src/services/api.ts | Backend integration layer (~834 lines) |
State management
No Redux/Zustand. State architecture:
| Pattern | Location | Purpose |
|---|---|---|
| React Context | hooks/useAuth.tsx | Auth state (user, token, login/logout) |
| Local useState | Each page/component | UI state, form, modal |
| Custom hooks | useAgentTransactions, useAgentOnlineBalanceLedger, useSupportedZeroxMethods | Data fetching with reload |
| localStorage | Auth tokens, user data, zerox methods cache (24h TTL) | |
| Custom Events | window.dispatchEvent | Cross-component sync |
Custom events
| Event | Constant | When dispatched |
|---|---|---|
agent-auth-token-changed | AGENT_AUTH_TOKEN_CHANGED_EVENT | Login / logout |
auth:unauthorized | — | Axios interceptor receives 401 |
Storage keys
| Key | Content |
|---|---|
agent_auth_token | Agent bearer token |
agent_user_data | Agent profile (JSON) |
Authentication flow
sequenceDiagram
participant U as Agent user
participant A as Agent Portal
participant B as Backend
U->>A: Enter username/email + password
A->>B: POST /agent-auth/login
alt OTP required (2FA)
B-->>A: needsOtp + pendingToken
U->>A: Enter OTP
A->>B: POST /agent-auth/verify-otp
end
B-->>A: accessToken + agent profile
A->>A: Save token to localStorage
- Header:
Authorization: Bearer {token} - 401 → dispatch
auth:unauthorized→ auto logout ProtectedRouteredirects to/loginif not authenticated
Environment variables
| Variable | Required | Description | Default |
|---|---|---|---|
REACT_APP_API_BASE_URL | Yes | Backend API base URL | http://localhost:3001/api |
REACT_APP_TURNSTILE_ENABLED | No | Enable Cloudflare Turnstile | false |
REACT_APP_TURNSTILE_SITE_KEY | When Turnstile enabled | Site key | '' |
REACT_APP_APP_NAME | No | Display app name | Kiosk Gaming — Agent |
REACT_APP_CLIENT_TELEGRAM_SUPPORT_URL | No | Telegram support link | — |
REACT_APP_CLIENT_ANDROID_APK_URL | No | Android APK download link | — |
REACT_APP_CLIENT_IOS_VIDEO_URL | No | iOS setup video | — |
PORT | No | Dev server port | 3003 |
warning
Backend must set AGENT_FRONTEND_URL to the app origin so payment redirects to /payment/success, /payment/cancelled, /payment/error.
npm scripts
| Script | Description |
|---|---|
npm start | Dev server port 3003 (CRACO) |
npm run build | Production build → build/ directory |
npm test | Run tests (CRACO) |
Special configuration
CRACO + Monorepo UI
craco.config.js imports configureKioskgamingUi from ../packages/ui so webpack resolves the shared UI package.
Capacitor
Not included — this is a pure web app with no native wrapper.
Service Worker (PWA)
public/sw.js+serviceWorkerRegistration.ts- Registers only when
NODE_ENV === 'production'
Deploy (Static SPA)
| File | Platform |
|---|---|
public/_redirects | Netlify, Cloudflare Pages — /* → /index.html 200 |
public/.htaccess | Apache — rewrite non-file routes → index.html |
public/web.config | IIS / Azure Static Web Apps |
cd kioskgaming_agent
npm install
npm run build
# Deploy build/ directory to static host
Shared UI package
Shared components from @kioskgaming/ui:
PortalCreditTransactionsLedger,PortalUsdWalletLedgerTableCreditTransactionDetailModal,UsdWalletTransactionDetailModalWithdrawOtpStep,WithdrawBlockedAlertFormField,Modal,Button,Input,Select,TextareaPlayerFraudIndicatorsPanel,SupportDownloadRail
Overview diagram
flowchart TB
subgraph Client["kioskgaming_agent"]
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| AgentAPI["/agent/*"]
API --> AuthAPI["/agent-auth/*"]
API --> PaymentAPI["/payment/*"]
end
subgraph Storage["Browser"]
Auth --> LS["localStorage: agent_auth_token"]
end