This is a Next.js project bootstrapped with create-next-app.
First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 with your browser to see the result.
You can start editing the page by modifying app/page.js. The page auto-updates as you edit the file.
This project uses next/font to automatically optimize and load Geist, a new font family for Vercel.
To learn more about Next.js, take a look at the following resources:
- Next.js Documentation - learn about Next.js features and API.
- Learn Next.js - an interactive Next.js tutorial.
You can check out the Next.js GitHub repository - your feedback and contributions are welcome!
The easiest way to deploy your Next.js app is to use the Vercel Platform from the creators of Next.js.
Check out our Next.js deployment documentation for more details.
- Introduction
- System Architecture
- Frontend Components
- Backend Services
- Game Mechanics
- Authentication Flow
- Database Structure
- Real-time Communication
- Deployment
- Potential Issues and Solutions
- Future Enhancements
CoinQuest is a cryptocurrency-themed gaming platform that offers multiple games including Aviator (crash game) and Opinion Trading. The platform features a points-based system, real-time chat, and user authentication via crypto wallets.
The application is built using:
- Frontend: Next.js, React, Tailwind CSS
- Backend: Node.js, Express, Socket.io
- Database: PostgreSQL
- Authentication: Privy for wallet-based authentication
- Game Engine: Unity WebGL for the Aviator game
The system follows a client-server architecture with real-time communication:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ Next.js Client │◄────►│ Express Server │◄────►│ PostgreSQL │
│ │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
▲ ▲
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ │ │ │
│ Socket.io │◄────►│ Socket.io │
│ Client │ │ Server │
│ │ │ │
└─────────────────┘ └─────────────────┘
- Client-Side: Next.js application with React components
- Server-Side: Express server with Socket.io for real-time communication
- Database: PostgreSQL for persistent storage
- Real-time Communication: Socket.io for game state and chat
-
RootLayout (
app/layout.js):- Provides the shell for all pages
- Manages SEO metadata dynamically based on routes
- Integrates Privy authentication provider
- Includes Google Analytics and Tag Manager
- Applies global styles and fonts
-
Navbar (
components/Navbar.js):- Handles user authentication display
- Shows user points and level
- Provides dropdown menu for user actions
- Responsive design for mobile and desktop
-
Footer (
components/Footer.js):- Displays site information and links
- Present on all pages
-
Landing (
components/Landing.js):- Main landing page component
- Displays featured games
- Includes SpinWheel for daily rewards
- Shows chat room for authenticated users
- Handles socket connection for chat
-
SpinWheel (
components/SpinWheel.js):- Daily reward mechanism
- Limited to 10 spins per day
- Updates user points on successful spins
-
Login (
components/Login.js):- Integrates with Privy for wallet authentication
- Handles user registration and login
- Stores user data in localStorage
-
NamePopup (
components/NamePopup.js):- Allows users to set a custom nickname
- Appears for new users or users with auto-generated names
-
MainAviator (
components/Aviator/MainAviator.js):- Container component for the Aviator game
- Organizes layout of game elements
-
Crash (
components/Aviator/Crash.js):- Integrates Unity WebGL game
- Manages game state synchronization
- Handles cashout functionality
- Displays multiplier and game status
-
Bet (
components/Aviator/Bet.js):- Provides betting interface
- Fixed bet amount of 50 points
- Disables when game is in progress
-
History (
components/Aviator/History.js):- Displays history of previous game rounds
- Color-codes multipliers based on value
-
AviatorContext (
components/Aviator/AviatorContext.js):- Provides state management for the game
- Handles socket communication
- Manages game state, bets, and cashouts
- OpinionTradingPage (
app/opinion-trading/page.js):- Main component for opinion trading
- Displays questions and betting options
- Handles bet placement and confirmation
- Shows user's placed bets
- Calculates dynamic multipliers
-
ChatRoom (
components/Chatroom/ChatRoom.js):- Main chat container
- Manages socket connection
- Handles message sending and receiving
- Supports emoji reactions
- Includes typing indicators and notifications
-
ChatHeader (
components/Chatroom/ChatHeader.js):- Controls for minimizing and switching tabs
- Shows online user count and notifications
-
MessageList (
components/Chatroom/MessageList.js):- Displays chat messages
- Supports message reactions
-
ChatInput (
components/Chatroom/ChatInput.js):- Input field for typing messages
- Emoji picker integration
- Send button and typing indicators
-
UsersList (
components/Chatroom/UsersList.js):- Shows online users
- Displays user nicknames and status
-
NicknameInput (
components/Chatroom/NicknameInput.js):- Allows users to change their nickname in the chat other wise wallet address is visible
- Main Server (
server/index.js):- Express server configuration
- Socket.io initialization
- API endpoints for health checks and user info
- Shared state management
-
Chat Socket (
server/chatSocket.js):- Handles chat room management
- Processes messages and reactions
- Manages user presence and status
- Implements slow mode and message validation
-
Game Socket (
server/gameSocket.js):- Manages Aviator game state
- Handles bet placement and cashouts
- Broadcasts game events to clients
- Maintains game history
- Database (
server/database.js):- PostgreSQL connection setup
- User management functions
- Game data persistence
- Points and bets tracking
The Aviator game is a "crash" style game where players place bets and try to cash out before the multiplier crashes:
-
Game States:
waiting: Accepting bets before the round startscountdown: 3-second countdown before flightplaying: Multiplier increasing, players can cash outended: Game crashed, round over
-
Betting Mechanism:
- Fixed bet amount (50 points)
- Bets can be set anytime but will be placed during the
waitingstate - One bet per user per round
-
Cashout Mechanism:
- Players must manually cash out during the
playingstate - Payout = bet amount × current multiplier
- Once cashed out, cannot cash out again in the same round
- Players must manually cash out during the
-
Visual Implementation:
- Unity WebGL for the airplane animation
- React overlay for UI controls and multiplier display
- Socket.io for real-time game state updates
Opinion Trading is a prediction market where users bet on binary (yes/no) questions:
-
Question Structure:
- Title and detailed description
- Expiry date when betting closes
- Binary outcome (yes/no)
-
Betting Mechanism:
- Fixed bet amount (100 points)
- Users can place one bet per question
- Cannot bet on expired questions
-
Multiplier Calculation:
- Dynamic multipliers based on the pool ratio
- Formula: (1 - FEE_PERCENTAGE) * totalPool / sumSide
- 5% platform fee (FEE_PERCENTAGE = 0.05)
-
User Interface:
- Main question display with yes/no buttons
- Sidebar with other available questions
- User's placed bets section
- Confirmation modal for placing bets
The application uses Privy for wallet-based authentication:
-
Login Process:
- User clicks "Login" in the Navbar
- Privy modal opens with options (wallet, email, SMS, Google, Twitter)
- User authenticates with chosen method
- On successful authentication, user data is stored in localStorage
- Custom event
cqUserChangedis dispatched to notify components
-
User Data Structure:
{ address: "0x123...", // Wallet address points: 1000, // User points name: "User123", // Display name (work still in progress) spinsToday: 3 // Daily spin count }
-
Session Management:
- User session persists in localStorage
- Components retrieve user data from localStorage on mount
- Socket connections include user address for identification
-
Name System:
- New users get auto-generated names
- NamePopup allows setting custom names
- Names are stored in the Postgres and synced across devices
The PostgreSQL database includes the following tables:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
wallet_address VARCHAR(42) UNIQUE NOT NULL,
nickname VARCHAR(50),
points INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE TABLE bets (
id SERIAL PRIMARY KEY,
wallet_address VARCHAR(42) NOT NULL,
question_id INTEGER NOT NULL,
choice VARCHAR(10) NOT NULL,
stake_amount INTEGER NOT NULL,
multiplier DECIMAL(10,6) NOT NULL,
potential_return DECIMAL(10,6) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (wallet_address) REFERENCES users(wallet_address)
);CREATE TABLE questions (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
details TEXT,
expiry TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);creats a history.js in local and stores the history there and change it constantly
The application uses Socket.io for real-time communication between the client and server:
- /game: For Aviator game events
- /chat: For chat functionality
- game:init: Initial game state
- game:update: Pool updates
- game:countdown: Countdown phase
- game:start: Game starts
- game:multiplier: Multiplier updates
- game:cashout: Cashout events
- game:crash: Game end/crash
- game:history: History updates
- chat:joined: User joined a room
- chat:newMessage: New message received
- chat:messageReaction: Message reaction
- chat:userJoined: User joined the chat
- chat:userLeft: User left the chat
- chat:onlineUsers: List of online users
- chat:error: Error messages
- chat:userTyping: Typing indicators
The application is deployed using Google Cloud Run:
- Next.js application containerized with Docker
- Deployed to Cloud Run
- Environment variables set in Cloud Run configuration
- Custom domain with SSL
- Express server containerized with Docker
- Deployed to Cloud Run
- Socket.io configured for Cloud Run (WebSocket support)
- Environment variables for database connection
- PostgreSQL on Google Cloud SQL
- Connection secured with private IP and Cloud SQL Proxy
- Regular backups configured
Problem: WebSocket connections may fail in certain network environments.
Solution:
- see the env file if the SOCKET_URL is set correct
Problem: Temporary database unavailability.
Solution:
- See in env if you have set the Public IP or Private IP
- try running test.js in root
Problem: Wallet connection issues or session expiration.
Solution:
- Clear data of website
- See if you are able to connect to db.
- Firefox metamask extension sometimes doesn't work properly try reinstalling it.
-
Additional Pages:
- Givin TODO.txt in root dir
-
Spin Wheel Logic (doesn't reset daily spins):
- eithr do this in db -- ALTER TABLE users ALTER COLUMN last_spin_date TYPE DATE USING last_spin_date::date;
- or find some other solution in app/api/spin/route.js line 53
-
Name Popup:
- On New user login it should show a popup asking for name
- That Logic need to be fixe (currenty happning in both Navbar.js and Logic.js)
-
SEO Changes:
- Add Images of website.
- Do everything given in TODO.