GS

GameStar365

Player Web V2 • Docs

Live • Production Ready • Multilingual (7 locales)

GameStar365 Player Web V2

Next-generation casino & sports gaming platform — blazing-fast Next.js 15 frontend with glass-morphism casino theme, 7-language i18n, real-time socket updates, and modular player account suite.

29Routes
30+API Groups
84Components
v1.0.0 Private Next.js 15 React 19 TypeScript Tailwind Redux Toolkit React Query

⚡ Quick Install

● npm
npm install
cp .env.example .env.local
npm run dev
→ http://localhost:3000/bn
Default locale bn • Dark theme • Div-scroll architecture

Introduction

What & why — objective and scope

GameStar365 Player Web V2 is the customer-facing frontend for the GameStar365 iGaming ecosystem. It delivers a premium casino experience — slots, live-casino, sports, lottery, fish-shooting, crash & arcade — through a single responsive web app optimized for mobile-first emerging markets (Bangladesh, Thailand, Indonesia, Malaysia).

Objective
Replace legacy playerUi with a modern, maintainable, SEO-friendly platform that loads instantly, supports 7 locales (bn/en/th/id/ms/it/ar with RTL), and handles real-money flows (deposit/withdraw, KYC, VIP, spin-bonus, promotions) securely.
Scope
All player journeys: discovery (hero slider, hot/top/exclusive games, providers, categories), authentication (login/register, phone OTP), wallet (deposit/withdraw + gateway allocation), account (KYC, balance, turnover, bet history, referrals, gift/spin bonuses), promotions, VIP, support chat, notifications & search.

Key Objectives

  • Performance: div-scroll architecture, AppImage lazy-load 200px before viewport, AVIF/WebP, 30-day image cache, bundle-optimized imports.
  • Consistency: single source of truth — colors in globals.css :root, endpoints in config/api.ts, icons in components/icons.
  • Reliability: Axios refresh queue, socket.io real-time, React Query staleTime tiers (30s realtime → 1h static).
  • Compliance: CSP, X-Frame nosniff, protected routes via middleware cookie, SEO JSON-LD + sitemap.

Problem Statement

The pain points this rebuild solves

Legacy Fragmentation

Previous playerUi scattered tokens across files, duplicated API URLs, no typed contracts — hard to onboard, easy to break.

Poor Perceived Performance

Images blocked render, layout shifted, no lazy strategy — users saw white screens before banners.

Unscalable i18n & Routing

Locale hard-coded, RTL unsupported, 404s not localized — adding a language meant touching dozens of files.

Fragile Finance Flows

Deposit/withdraw lacked session init, gateway allocation & withdrawal-capability checks — causing failed transactions and support load.

Solution thesis: A design-token-driven Next.js app with middleware locale gating, centralized API config, AppImage preloading, and Redux+Query state that persists auth/ui to localStorage. One place to change each concern. Visit /bn/design-system for live component gallery.

Features

Player-facing capabilities at a glance

Game Discovery

Hot / Top / Exclusive sliders, category-wise games, provider modals, favorites, search with debounce.

Auth & Security

Login/Register, phone OTP, refresh-token queue, protected routes, XSS/CSP headers, cookie sync.

Wallet

Deposit/withdraw per method, automated gateway allocation, session init, history, verify-deposit.

Account Suite

KYC submit/status, password change, turnover, bet results, sports wagers, referral commissions.

VIP & Bonuses

VIP overview/levels/rules/history, spin-bonus wheel (@mertercelik), gift bonus, promotions claim.

Engagement

Banners, promotions, announcements, popup, advertisements, sponsors, social, support chat & notifications.

Design System

/bn/design-system — live demos of buttons, modals, icons, tokens, hooks, Redux slices.

Global i18n

7 locales (bn/en/th/id/ms/it/ar) with RTL, next-intl, per-page metadata, flag + native name.

Real-time

Socket.io client, notification socket handler, announcement marquee, balance polling (30s).

Tech Stack

Frameworks, libraries & tooling

Next.js 15.5.20Framework
React 19.1.0UI Library
TypeScript 5.8Language
Tailwind 3.4Styling
Redux Toolkit 2.5State
TanStack Query 5.75Data Fetch
Axios 1.9HTTP Client
Socket.IO 4.8Realtime
next-intli18n
next-themesTheming
Swiper 12.2Carousel
react-icons / lucideIcons
DependencyVersionPurpose
@mertercelik/react-prize-wheel^1.1.0Spin wheel bonus
class-variance-authority^0.7.1Button variant CVA
clsx + tailwind-merge^2.1.1 / ^3.3.0cn() utility
lucide-react / react-icons^1.14 / ^5.5.0Icons (fa6 + lucide)
moment^2.30.1Date formatting (replace with date-fns recommended)
react-intersection-observer^9.16.0AppImage lazy trigger
react-phone-number-input^3.4.17Phone OTP field (dark pill styling)
react-qr-code^2.2.0QR for app-download / deposit
use-sound^5.0.0Spin tada/fanfare sounds
sharp^0.34.1Next.js image optimization
LayerChoicesWhy
RenderingApp Router, RSC + Client componentsSEO + interactivity per route
StylingTailwind + CSS variables (globals.css)Single token file drives theme
StateRedux (auth/ui/game/notification) + QueryPersisted auth + cached API
AuthBearer token + refresh queue + auth cookieProtected routes via middleware
MediaAppImage + sharp, AVIF/WebP, remotePatternsInstant perceived load
ToolingESLint 9, TS strict, autoprefixer, postcssDX + build safety

System Architecture

Folder map, data flow & design principles

🌐 Middleware

Locale detect → redirect /bn • cookie gs365_locale • protected route guard

src/middleware.ts
📄 App Router

[locale]/layout + page per route • SEO metadata • sitemap.ts

src/app/[locale]
🧩 Providers

Redux Provider + QueryClient + next-intl + next-themes

components/layout/Providers
🎣 Hooks + Store

useAppDispatch, useModal, useNotification • slices: auth/ui/game/notification

🔌 API Layer

apiClient (Axios + refresh queue) • ENDPOINTS • React Query keys + CACHE_TIME

🎨 UI Kit

Button, Modal, AppImage, GameCard, HeroSlider — glass + dark navy tokens

Folder Structure — Full (84 files, 19 folders)

src/ ├── app/ # Next.js App Router — 29 routes │ ├── [locale]/ # 7 locales │ │ ├── layout.tsx — Root layout + SEO meta + DictionaryProvider │ │ ├── page.tsx — Home (HomeContent: hero + categories + hot/top/exclusive) │ │ ├── login/page.tsx, register/page.tsx, favorites/, hot-games/, top-games/, exclusive-games/, category-wise-games/ │ │ ├── category/[id]/, provider/[id]/, providers/[id]/, promotions/[id]/, deposit/[methodId]/, withdraw/[methodId]/ │ │ ├── account-information/[section]/ — 16 sub-components (KYC, turnover, betHistory...) │ │ ├── vip/, vip-v2/, vip-details/, affiliate-program/, app-download/, about-us/, privacy-policy/, terms-and-conditions/ │ │ ├── [...notFound]/page.tsx — locale-aware 404 │ │ └── loading.tsx (×6) + design-system/page.tsx — showcase │ └── layout.tsx not-found.tsx (→/bn) sitemap.ts (42 URLs × locales) ├── components/ — 84 files │ ├── buttons/Button.tsx # CVA 8 variants × 8 sizes icons/Icon.tsx auth/*3 category/*2 │ ├── layout/*10 # AppShell, TopNavbar, BottomNavbar, DesktopSidebar(260px), FooterV2, Providers │ ├── modals/*10 # Modal, StatusModal, Login/Register, Filter, Provider, WalletModal(1500L) │ ├── game/*13 # GameCard, GameSlider, Hot/Top/Exclusive, PromotionCard, FilterBar/Pills │ ├── hero/*2 deposit/*7 notifications/*4 popup/*1 search/*1 seo/*2 spin/*3 sponsors/*2 sports/*3 SupportUs/*7 ui/*10 Advertisement/*1 ├── config/api.ts # ⭐ 429L — 30 groups ENDPOINTS + QUERY_KEYS + CACHE_TIME (STATIC/NORMAL/SHORT/REALTIME) ├── lib/ apiClient.ts(265L Axios+refresh queue) queryClient.ts(23L) seo.ts(78L JSON-LD) utils.ts(122L cn/formatCurrency) webVitals.ts(20L) ├── store/ — custom persist (NO redux-persist for React19) │ ├── index.ts # STORAGE_KEY gs365_state_v2, loadState/saveState 500ms throttled, only auth+partial ui │ └── slices/ authSlice(56L) uiSlice(88L theme/locale/sidebar/modal/settingsVersion) gameSlice(78L) notificationSlice(116L MAX 3/pos) ├── hooks/index.ts # 915L — 30+ hooks (useAuth, useBalance polling 5s, useGamePlay, usePopup frequency engine, useFavorites optimistic...) ├── i18n/ locales.ts(7 locales+RTL) messages/*.json # 10 files, 1430 keys, 36 namespaces — en.json source ├── contexts/*5 # ChatContext(347L socket+messages), SupportPanel, auth-context, ProviderContext, SearchContext ├── socket/index.ts # 61L useSocket + joinChat/leaveChat ├── styles/globals.css # ⭐ 596L — :root + [data-theme=light], glass, marquee, VIP animations ├── types/index.ts # 813L — User, Game, PublicProvider, Promotion, Transaction, VIP... └── middleware.ts # 59L SUPPORTED_LOCALES 7, PROTECTED_PATTERNS 4, gs365_locale cookie, matcher public/ assets/bank-logo+bank-banner/ images/logo+payment-method 24 SVGs profile/ referral/ spin/*.mp3+.gif gs365bd.apk(26.8MB) manifest.json robots.txt icons/icon.svg next.config.ts # 87L images AVIF/WebP, remotePatterns 8 hosts, CSP+6 security headers, cache 1y tailwind.config.ts # 166L brand/surface/text/border/status → CSS vars, radius 4xl/5xl, zIndex 60-1200, keyframes scripts/ # empty — only package.json scripts used
Div-scroll architecture: body {overflow:hidden; height:100dvh} — only #main-scroll scrolls. Prevents layout shift, keeps bottom nav fixed. Custom persist: localStorage gs365_state_v2 throttled 500ms — persists only auth + partial ui (theme, locale, modal, scrollPosition). sidebarOpen reset on load to avoid hydration mismatch.

Redux Store — 4 Slices (detailed)

SliceState ShapeKey Reducers / Selectors
auth 56L{user: User|null, isAuthenticated, isLoading}setUser, setTokens→tokenStorage, logout→clearTokens, updateBalance; selectUser/isAuthenticated/isAuthLoading
ui 88L{theme:'dark', locale, sidebarOpen:false, activeModal:null, scrollPosition:0, gameSiteImageSize:'horizontal', settingsLoaded, settingsVersion}setTheme/Locale, toggleSidebar, open/closeModal, setScrollPosition, setGameSiteImageSize; settingsVersion busts game images
game 78L{activeCategory:'all', activeProvider:null, searchQuery:'', sortBy:'popular', favorites: string[]}setActiveCategory/Provider, setSearchQuery/SortBy, toggleFavorite (splice), setFavorites, resetFilters; selectIsFavorite(factory)
notification 116L{items: NotificationItem[]} + MAX_PER_POSITION=3 FIFOaddNotification auto-id `notification_${counter}_${Date.now()}`, remove, clearAll; helpers notify.success(4000ms)/error(6000)/warning(5000)/info(4000)

Hooks Catalog — 30+ in `src/hooks/index.ts` (915L)

HookPurposeCache / Notes
useModalisOpen/open/close/togglelocal state
useAuthselectUser + loginMutation POST /api/users/login → setTokens + dispatchReact Query disabled ME (404 workaround)
useBalanceGET /api/balance/player/:id pollingevery 5s, stale 3s, enabled if auth
useVipOverviewGET /api/vip/overviewpolling 5s, nested data.data shape
useGamePlay / useFavorites / usePopupplay(gameId)+playSports, optimistic favorites, popup frequency enginepopup: every_visit / once_per_session (sessionStorage) / once_per_day (localStorage) / once_per_user; page targeting + priority sort
useSiteSettingsGET /api/settings?_=${Date.now()} cache-busteddispatches setGameSiteImageSize + document.title
useMenuProviders / useCategories / useBanners / useAnnouncement / useNotifications …All public listingsCACHE_TIME STATIC or NORMAL; notifications polling 20s stale 0
useScrollLock / useDebounce / useLocalStorage / useWindowSize / useCopyToClipboardUI utilitieswindowSize: mobile <768, tablet 768-1024

lib & SEO

queryClient.ts — 23L

stale 5m NORMAL, gc 30m, retry 2 exp backoff min(2^attempt*1000,30000), refetchOnWindowFocus dev only, mutations retry 0.

seo.ts — 78L

getOrganizationSchema, getWebsiteSchema (SearchAction /games?q={term}), getBreadcrumbSchema, getCanonicalUrl + getAlternateLinks hreflang. Used in [locale]/layout generateMetadata.

utils.ts — 122L

cn = twMerge(clsx), formatCurrency/formatNumber/formatCompactNumber, delay, generateId, debounce, truncate, getCdnUrl, getOrCreateGuestId → localStorage `chat_guest_id` g_${time36}${rand36}.

webVitals.ts — 20L + socket 61L

sendBeacon('/api/vitals'). Socket: io(SOCKET_URL) websocket+polling, emitEvent/joinChat/leaveChat.

Contexts — 5 providers

ContextLinesWhat it owns
ChatContext347LMessages/Chats, useSocket newMessage/chatUpdated, createChat + sendMessage + uploadAttachment → IMAGE_UPLOAD_URL, guestId fallback
ProviderContext52LMap<number,string> from game+sports providers, useProviderName(id)
auth-context41LWraps Redux selectUser → {id,username,role,vipLevel}, logout POST + clearTokens
SearchContext32LisOpen/openSearch/closeSearch/toggleSearch global
SupportPanelContext42LactiveTab home/messages/help/social + scroll lock

Installation & Setup

From clone to running locally

Prerequisites

  • Node.js ≥ 18.18 (Next 15 requires ≥18) • npm 9+
  • Access to API base URL (staging or prod) for NEXT_PUBLIC_API_BASE_URL
  • Fonts: public/fonts/display.woff2 + body.woff2 • Logo: public/images/logo.webp
bash — clone & install
git clone <repo-url> gs365-player-webV2
cd gs365-player-webV2
npm install
# or use npm ci for clean install
npm ci
bash — environment
cp .env.example .env.local
# Edit .env.local — minimum required:
NEXT_PUBLIC_API_BASE_URL=https://api-staging1615.trueeit.com
NEXT_PUBLIC_CDN_URL=https://cdn.gamestar365.com
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_APP_NAME="Game Star 365"
NEXT_PUBLIC_DEFAULT_LOCALE=bn
NEXT_PUBLIC_AUTH_TOKEN_KEY=gs365_token
NEXT_PUBLIC_ENABLE_DEVTOOLS=true
bash — run
npm run dev
# → http://localhost:3000  (auto-redirects to /bn)
# Production
npm run build && npm start
# Type check
npm run type-check
# Lint
npm run lint
ScriptCommandEnv file
devnpm run dev.env.local
buildnpm run build.env.production
startnpm start.env.production
stagingDOTENV_CONFIG_PATH=.env.staging npm run build.env.staging
Design-system route: visit http://localhost:3000/bn/design-system — interactive showcase of every component, tokens, slices, hooks, endpoints. Guard in prod via NEXT_PUBLIC_SHOW_DESIGN_SYSTEM=false + middleware.

Usage Guide

How to work with the codebase day-to-day

Routing — Full 29 routes (middleware gated)

Routepage.tsxProtectedNotes
/redirect→ /bn (reads gs365_locale cookie)
/:localeHome — hero + categories + events + game sections
/:locale/login & /registerAlso via AuthModal (xl with login-left-2.png)
/:locale/favoritesFavoritesContent + optimistic toggle
/:locale/hot-games, /top-games, /exclusive-games, /category-wise-gamesEach has loading.tsx skeleton
/:locale/category/[id]CategoryGamesContent dynamic
/:locale/provider/[id] & /providers/[id]?type=games&providerName=
/:locale/promotions & /promotions/[id]PromotionDetailsContent
/:locale/deposit & /deposit/[methodId]🔒DepositContent + SingleDeposit (gateway allocation 600s countdown)
/:locale/withdraw & /withdraw/[methodId]🔒WithdrawContent + capability check
/:locale/account-information & /account-information/[section]🔒16 sub-components: KYC, turnover, BettingHistory, SportsWagers, TransactionHistory, Referral, GiftBonus…
/:locale/vip, /vip-v2, /vip-detailsClassic + V2 redesign
/:locale/affiliate-program🔒ReferralInfo + commissions
/:locale/app-download, /about-us, /privacy-policy, /terms-and-conditionsStatic content (114 terms + 48 privacy keys)
/:locale/design-systemGuard with NEXT_PUBLIC_SHOW_DESIGN_SYSTEM=false in prod
/:locale/[...notFound]Locale-aware 404
Middleware matcher: /((?!_next/static|_next/image|favicon.ico|fonts|images|icons|profile|referral|spin|assets|manifest.json|robots.txt|sitemap.xml).*) — excludes static. Protected patterns: /deposit|/withdraw|/account-information|/affiliate-program require gs365_logged_in=true else redirect to /:locale.

Common Tasks

tsx — use translations
// Server component
import { getTranslations } from "next-intl/server";
const t = await getTranslations("games");
return <h1>{t("popularGames")}</h1>

// Client component
"use client";
import { useTranslations } from "next-intl";
const t = useTranslations("auth");
return <button>{t("login")}</button>
tsx — api call with React Query
import { useQuery } from "@tanstack/react-query";
import { api } from "@/lib/apiClient";
import { ENDPOINTS, QUERY_KEYS, CACHE_TIME } from "@/config/api";

const { data, isLoading } = useQuery({
  queryKey: QUERY_KEYS.PROMOTIONS.ALL,
  queryFn: () => api.get(ENDPOINTS.PROMOTIONS.LIST).then(r => r.data),
  staleTime: CACHE_TIME.NORMAL, // 5m
});
tsx — redux + notifications
import { useAppDispatch, useAppSelector } from "@/store/hooks";
import { selectUser } from "@/store/slices/authSlice";
import { notify } from "@/store/slices/notificationSlice";

const user = useAppSelector(selectUser);
dispatch(notify.success("Deposit Successful","৳500 added"));
tsx — AppImage & modals
import AppImage, { preloadImages } from "@/components/ui/AppImage";
<AppImage src="/games/slots.webp" alt="Slots" width={200} height={300} />
preloadImages(["/banner1.webp","/banner2.webp"]);

import Modal from "@/components/modals/Modal";
import { useModal } from "@/hooks";
const { isOpen, open, close } = useModal();
<Modal isOpen={isOpen} onClose={close} size="md" position="center"><div className="p-6">content</div></Modal>

Modules / Features Breakdown

Major files & what they own

ModulePath / CountResponsibility
Layoutcomponents/layout/*10AppShell (div-scroll root), TopNavbar(70px) + BottomNavbar(64px), DesktopSidebar 260px collapsible + pink active, FooterV2, Providers (Redux+Query+next-intl), SiteSettingsLoader
Buttonscomponents/buttons/Button.tsx — 177L CVA8 variants: primary (hot pink), secondary (outline→primary), outline, ghost, danger, success, accent (gold), glass; 8 sizes: xs h-7 … xl h-14 + icon/icon-sm/icon-lg; props: isLoading + Loader2, leftIcon/rightIcon, fullWidth
Modalscomponents/modals/*10Modal (240L, sm/md/lg/xl/2xl/fullscreen, center/bottom/top, backdrop blur 8px, portal, scroll lock) • StatusModal (278L, success/error/warning/info + ConfirmModal hook useStatusModal) • Login(218L) • Register(339L, 4 fields+OTP+terms) • AuthWrapper • Filter(218L sort/provider) • ProviderModal(133L 2xl) • WalletModal ~1500L (deposit→methods→amount→transfer→submit + withdraw, 600s countdown, receipt upload) • Claimable/Info NotificationModals
Gamecomponents/game/*13GameCard (3:4 aspect), GameSlider, Hot/Top/Exclusive/CategoryWise sections, EventCard, PromotionCard, FilterBar/Pills/Actions, Provider modal
Depositcomponents/deposit/*7DepositAmountProvider, DepositOptionsInfo, DepositPromotionSelect, DepositProvider, DepositSubmit, SessionAlertModal, WithdrawOptionsInfo — orchestrated by WalletModal
UI Kitcomponents/ui/*10AppImage (IO lazy 200px, skeleton/blur, preloadImages), Logo (LOGO_CONFIG), LanguageSelector, MenuItem (glass), GameGridSkeleton, Pagination, CustomSelect, NavigationProgress (#nprogress 3px hot pink)
Hero / Sponsors / Sportshero/*2, sponsors/*2, sports/*3, Advertisement/*1HeroSliderWrapper (Swiper), SponsorsClient (active-utils sponsors/ambassadors/licenses), SportsSection, AdvertisementSection
Spin / Support / Searchspin/*3, SupportUs/*7, search/*1, popup/*1, notifications/*4SpinWheel (react-prize-wheel) + SpinLauncher/Wheel, SupportPanel (4 tabs), SearchPopup (debounced), PopupContent (frequency engine), NotificationContainer + SocketHandler
i18ni18n/* + messages 10 fileslocales.ts 7 locales (bn🇧🇩 en🇬🇧 th🇹🇭 id🇮🇩 ms🇲🇾 it🇮🇹 ar🇸🇦 RTL), flags, defaultLocale from env; en.json 36 namespaces, ~1430 keys — see i18n details below

i18n — 36 namespaces, ~1430 keys (en.json source)

LocaleFlagNative NameStatus
bn🇧🇩বাংলা✅ default, complete
en🇬🇧English✅ source 1430 keys
th🇹🇭ภาษาไทย✅ complete
id🇮🇩Bahasa Indonesia🔲 from en
ms🇲🇾Bahasa Melayu🔲
it🇮🇹Italiano🔲
ar🇸🇦العربيةRTL true
NamespaceKeysExample
deposit87deposit.yourWallet
terms146terms.heading
aboutUs114aboutUs.hero
accountInfo101accountInfo.title
auth56auth.welcomeTo
common/footer/kyc …common.loading / footer.gameCategory
Also ships vi.json, zh.json, km.json placeholders not in Locale union — translate from en.json per README. All text via useTranslations() (client) or getTranslations() (server) + per-page generateMetadata title/description.

One-Place Customization

  • Colors/theme: src/styles/globals.css :root
  • Fonts: globals.css @font-face + --font-display/body
  • Logo: components/ui/Logo.tsx → LOGO_CONFIG
  • Endpoints: config/api.ts → ENDPOINTS
  • Buttons: components/buttons/Button.tsx → buttonVariants
  • Icons: components/icons/index.ts
  • Copy: i18n/messages/[lang].json
  • Default locale: middleware.ts → defaultLocale

API Reference

Centralized in src/config/api.ts — ENDPOINTS + QUERY_KEYS + CACHE_TIME

Base URL from NEXT_PUBLIC_API_BASE_URL (default http://localhost:8000). Timeout 30s. Auth via Authorization: Bearer <gs365_token>. All in src/config/api.ts 429L — 30 groups, typed QUERY_KEYS, 5 CACHE_TIME tiers. Axios request interceptor excludes PUBLIC_ENDPOINTS; refresh queue with failedQueue + isRefreshing flag.

GroupKey ENDPOINTSMethod
AUTHLOGIN, REGISTER, LOGOUT, REFRESH, ME, FORGOT_PASSWORD, VERIFY_EMAIL/PHONEPOST /api/users/login
USERPROFILE, BALANCE/:userId, FAVORITES, ADD/REMOVE_FAVORITE, CHANGE_PASSWORDGET /api/balance/player/:id polling
GAMESPLAY, SPORTS_PLAY, BY_PROVIDER/:id, BY_CATEGORY/:catPOST /api/games/play {userId,gameId,betAmount:0}
PUBLICproviders, categories/:id, hot/top/exclusive/category-wise-games, banners/home, promotions? id=GET /api/public/banners/home
CATEGORY_*CATEGORY_GAMES, CATEGORY_WISE_PROVIDER/:id, CATEGORY_PROVIDER (type+providerId+categoryId)GET /api/public/category-provider
PAYMENTPAYMENT_METHOD, DEPOSIT_TRANSACTION, WITHDRAW_CAPABILITY, ALLOCATE_GATEWAY, SESSION_INIT/ACTIVE, VERIFY_DEPOSIT_AMOUNT, TRANSACTIONS/playerPOST /api/payment-session/init
FINANCEDEPOSIT_METHODS, WITHDRAW_METHODS, HISTORYGET /finance/deposit/methods
VIP / BONUSvip/overview|levels|rules|history|redeem, spin, gift-bonus, referral-stats/commissionsGET /api/vip/overview
USER DATAturnover, bet-results, sports-wagers/stats, transactions, user-phones (OTP)GET /api/turnover? userId & status
CONTENTbanners, promotions, announcement, popup, advertisement, active-utils, social-platforms, events, faqGET /api/public/popup
CHATchats, chats/count-unread, messages/send-message, messages/user-adminPOST /api/messages/send-message
SEARCH / COUNTRIESPUBLIC SEARCH, COUNTRIESGET /api/public/search?q=& /api/countries
Request — login
POST /api/users/login
Content-Type: application/json

{
  "username": "player01",
  "password": "••••••••"
}
Response — ApiResponse
{
  "success": true,
  "status": 200,
  "message": "Login successful",
  "data": {
    "accessToken": "eyJ...",
    "refreshToken": "eyJ...",
    "user": { "id": 123, "username": "player01" }
  },
  "traceId": "abc-xyz",
  "timestamp": "2026-09-01T00:00:00Z"
}
ts — apiClient usage
import { api, apiClient } from "@/lib/apiClient";
import { ENDPOINTS, QUERY_KEYS } from "@/config/api";

// typed helpers
const res = await api.get<Promotion[]>(ENDPOINTS.PROMOTIONS.LIST);
// raw axios
const raw = await apiClient.post(ENDPOINTS.AUTH.LOGIN, { username, password });
Cache TierValueUse
STATIC1hSite config, categories
NORMAL5mBanners, promotions
SHORT1mLists
REALTIME30sBalance, jackpots
NEVERNo refetch

Configuration

Env vars, Tailwind & Next config

VariableDefault / ExamplePurpose
NEXT_PUBLIC_APP_NAMEGame Star 365Document title + SEO
NEXT_PUBLIC_APP_URLhttps://gamestar365.com (dev) / staging1615v2 / production1615v2Canonical, sitemap BASE_URL, OG
NEXT_PUBLIC_APP_ENVdevelopment | staging | productionEnv badge
NEXT_PUBLIC_API_BASE_URLhttps://api-staging1615.trueeit.com → api.trueeit.com prodapiClient baseURL + socket fallback
NEXT_PUBLIC_SOCKET_URL= API_BASE_URL if emptySocket.IO URL
NEXT_PUBLIC_API_TIMEOUT30000Axios timeout ms
NEXT_PUBLIC_CDN_URLhttps://cdn.gamestar365.com → production1615v2 in prodgetCdnUrl() base
NEXT_PUBLIC_IMAGE_CACHE_TTL300Image cache
NEXT_PUBLIC_AUTH_TOKEN_KEYgs365_tokenlocalStorage token
NEXT_PUBLIC_AUTH_REFRESH_TOKEN_KEYgs365_refreshRefresh token
NEXT_PUBLIC_DEFAULT_LOCALEbnMiddleware fallback
NEXT_PUBLIC_DEFAULT_COUNTRY_CODEBDPhone input default
NEXT_PUBLIC_ENABLE_DEVTOOLStrue dev & staging, false prodReact Query devtools + redux devTools
NEXT_PUBLIC_ENABLE_MOCK_APIfalseMock toggle (unused)
NEXT_PUBLIC_AFFILIATE_URLhttps://affiliate.gs365bd.comAffiliate link
NEXT_PUBLIC_IMAGE_BASE_URLhttps://glorypos.com/image-uploadIMAGE_UPLOAD_URL /upload (chat attachment)
.env fileAPIAPP_URL
.env (dev)api-staging1615.trueeit.comgamestar365.com
.env.stagingapi-staging1615.trueeit.comstaging1615v2.trueeit.com
.env.productionapi.trueeit.comproduction1615v2.trueeit.com
Env precedence: Next.js loads .env.local (dev) → .env.production (build). All vars are NEXT_PUBLIC_ (client-safe, no secrets).
tailwind.config.ts — 166L
Colors: brand.primary/hover/active, secondary, accent, surface(5), text(5), border(3), status(8) all → CSS vars. Fonts display/body/mono, radius 4xl-5xl, zIndex 60-1200 (modal 1000, notification 1100), keyframes slideInUp/Down/Right/Left, fadeIn, shimmer, pulse, notificationSlide. DarkMode ['class'].
next.config.ts — 87L
Images: AVIF/WebP, deviceSizes 320-1920, imageSizes 16-384, cache 30d, allow SVG. CSP + 6 security headers (see below). remotePatterns: *.trueeit.com, *.netlify.app, bshots.egcvi.com, *.egcvi.com. compiler.removeConsole in prod, optimizePackageImports: @reduxjs/toolkit.

Security Headers (on `/(.*)`)

HeaderValue
X-DNS-Prefetch-Controlon
X-Frame-OptionsSAMEORIGIN
X-Content-Type-Optionsnosniff
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policycamera=() microphone=() geolocation=(self)
Content-Security-Policydefault-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self' https://*.trueeit.com ws: wss:; frame-src youtube(+nocookie)
Cache-Control/_next/static & /fonts → public, max-age=31536000, immutable

SEO, PWA & Public Assets

SEO — sitemap.ts (50L) + layouts

BASE_URL × 7 locales × 6 static routes = 42 URLs, changeFreq daily/weekly, priority 1/0.8, hreflang alternates. Root layout metadata template `%s | Game Star 365`, viewport maxScale 1, themeColor #0d1b4b. [locale]/layout generateMetadata from Dictionary meta → OG/Twitter large_image, icons, manifest.

PWA — manifest.json + robots.txt

manifest: name GS365, start_url /, display standalone, icons 512 maskable, categories games/entertainment. robots: Allow /, Disallow /api /admin /_next /404, Sitemap gamestar365.com/sitemap.xml.

public/ — 26.8 MB APK

assets/bank-logo+bank-banner (brac/dbl), images/logo.png+login.webp+payment-method 24 SVGs (bKash etc.), profile/lady-avatar.jpg, referral/flow+leaderboard+avatar, spin .mp3+.gif, gs365bd.apk, icons/icon.svg, og-image.jpg 1200×630 needed.

Scripts & CI

scripts/ empty (0 files). No Dockerfile / .github workflows — deployment is `next build && next start` to trueeit hosts. No tests (*.test.* none). Add scripts/check-env, seed-i18n.

env — .env.example
NEXT_PUBLIC_APP_NAME="Game Star 365"
NEXT_PUBLIC_APP_ENV="development"
NEXT_PUBLIC_API_BASE_URL="https://api-staging1615.trueeit.com"
NEXT_PUBLIC_CDN_URL="https://cdn.gamestar365.com"
NEXT_PUBLIC_AUTH_TOKEN_KEY="gs365_token"
NEXT_PUBLIC_AUTH_REFRESH_TOKEN_KEY="gs365_refresh"
NEXT_PUBLIC_ENABLE_MOCK_API=false

Testing

Current state & how to add tests

Glob `**/*.test.*` + `**/*.spec.*` → 0 files. No jest/vitest/playwright/cypress, no __tests__/ folder. package.json has only lint + type-check. Use these verification steps today:

bash — verification
npm run type-check   # tsc --noEmit — strict types
npm run lint         # eslint 9 + eslint-config-next
npm run build        # exposes missing env, broken imports, route errors
# Manual smoke: visit /bn/design-system — every component has live demo
Recommended next: Add Vitest + Testing Library for slices/hooks, Playwright for deposit/withdraw E2E, and MSW for API mocking. Gate /design-system with visual regression (Chromatic/Percy).
  • Unit: store/slices/*, lib/utils.ts, apiClient normalizeError
  • Integration: auth flow + refresh queue, React Query keys
  • E2E: locale redirect, protected routes, game launch, payment session

Known Limitations / Challenges

Honest trade-offs

🔒 No Test Coverage + No CI

0 test files, no GitHub workflows, no Dockerfile — regression relies on manual QA + /design-system page.

🌐 i18n Incomplete

vi/id/km+zh placeholders not in Locale union — need translate from en.json; Arabic RTL partially tested; 36 namespaces cross-check needed.

🖼️ Missing Assets

public/fonts/display.woff2+body.woff2, logo.webp, og-image.jpg 1200×630, icons 192/512 missing → fallback placeholder.svg; gs365bd.apk 26.8MB ships.

🔑 Token in localStorage

Bearer + refresh in LS; CSP allows unsafe-eval/inline — tighten. httpOnly cookie stronger; refresh queue handles 401 but no rate-limit.

📱 Div-scroll Quirks + Monolith

Body 100dvh locked — embeds expecting window scroll break. WalletModal 1500L monolith should split; moment 2.30 heavy vs date-fns.

📦 Dual Icons + CSP

Both react-icons & lucide-react used — consolidate. CSP script-src unsafe-* needed for Next inline — narrow in prod. seo TODO: dynamic game slugs commented out in sitemap.

Future Improvements / Roadmap

What to build next (from README)

BannerCarousel & GameCategoryTabs
New UI components — components/ui/BannerCarousel.tsx + GameCategoryTabs.tsx
DesktopSidebar polish + RegisterModal
Auth modal parity with LoginModal, sidebar collapse states
Route expansion
Games, Promotions, Profile pages under [locale]/ with loading.tsx skeletons
PWA + Offline
manifest.json already present — add service worker, icon-192/512, install prompt
Performance
Replace moment, optimizePackageImports for Swiper, bundle analyzer CI gate
Testing & CI
Vitest + Playwright + GitHub Actions (type-check → lint → build → preview)
Security hardening
httpOnly refresh cookie, strict CSP, rate-limit login, device fingerprint

Contributing Guidelines

How to contribute safely

Workflow

bash
git checkout -b feat/your-feature
# Make changes — respect ONE-PLACE rules in README
npm run lint && npm run type-check
npm run build
# Push & open PR — include screenshots for UI changes

Conventions

  • Components: PascalCase files, marks global primitives (Button, Modal, AppImage)
  • Tokens: never hard-code colors — use CSS vars
  • API: add endpoint to ENDPOINTS + QUERY_KEYS (no inline URLs)
  • Copy: update all messages/*.json (at least en) or add TODO flag
  • Commits: feat: fix: docs: chore:
PR Checklist: type-check passes, lint clean, no hardcoded API URLs, i18n keys added, dark+light screenshots, middleware locale tested, AppImage has alt.

License

Proprietary — all rights reserved

package.json marks private: true. No public license file is shipped. All code, assets, and brand (GameStar365, logos, game thumbnails) are proprietary to the operator. Do not distribute without written permission.

If you need a license file: add LICENSE at repo root (e.g., proprietary or commercial) and update package.json → license.
GameStar365 Player Web V2

Next.js 15 • React 19 • TypeScript • Tailwind • Redux • React Query • Socket.IO • 7 Locales • Docs theme mirrors globals.css — deep navy #102979, hot pink #e91e8c, gold #ffd700, glass morphism.

↑ Back to top Start reading

Built for TrueIT Projects • Source project: gs365-player-webV2 • Docs standalone at GameStar365-Docs/docs • Press ? to focus search • Smooth scroll + copy buttons enabled