This is a full-stack web development project focused on building a single-page application (SPA) with user authentication, multiplayer gaming, real-time statistics, and game history tracking.
- Secure user authentication
- Comprehensive user management
- Real-time live chat
- Online multiplayer gaming
- Live performance statistics
- Game history tracking
- Tournament creation and participation
- Dynamic leaderboards
- HTML/HTML5
- CSS/CSS3
- Typescript
- NodeJs
- Fastify
- SQLite3
- Docker
Follow the steps below to set up the project:
-
Clone the repository:
git clone https://github.com/oussamakami/gamepad.git cd gamepad
-
Install dependencies:
- requires node verion 18+
npm install
-
Create a
.env
file:touch .env
-
Configure environment variables:
The
.env
file should contain the following:PORT = <server_port> JWT_SECRET = <64_character_long_secure_string> PICTURES_PATH = <absolute_path_to_profile_pictures_directory> SMTP = <SMTP server url> SMTP_PORT = <SMTP server port> SMTP_USER = <SMTP server user/email> SMTP_PASS = <SMTP password/app_password> CLIENT_ID = <Google OAUTH2 Project Client ID> CLIENT_SECRET = <Google OAUTH2 Project Client Secret>
To generate a secure
JWT_SECRET
, you can use this command:head /dev/urandom | base64 | head -c 64
PORT = 3000 JWT_SECRET = uxgK8HyrB6sE/0eLkQsgGQxZwOz1Qrdt7giegJRm31aoP4PVPzFNYXMVszsoYbQG PICTURES_PATH = /home/linux/gamepad/back-end/figures SMTP = smtp.gmail.com SMTP_PORT = 465 SMTP_USER = [email protected] SMTP_PASS = abcd efgh ijkl mnop CLIENT_ID = 420389808456-6eyfjlkxbk78xzboqiv8lsnrasid0cmd.apps.googleusercontent.com CLIENT_SECRET = QADSNG-OKtDL5KdUI8r9iJSh3JnXeBnbef8
-
Available NPM Scripts:
-
npm run build
Compiles the TypeScript code into JavaScript. -
npm run clean
Removes the compiled JavaScript code. -
npm run api
Starts the backend server only. -
npm start
Builds and runs both frontend and backend. The website will be available athttp://localhost:5500
.
-
- Navigation
- Top Navigation
- Profile Name
- Profile Picture
- Fullscreen Toggle
- Light/Dark Mode Toggle
- Settings Shortcut
- Notifications Drawer
- User Search Bar
- Sidebar Toggle
- Side Navigation
- App Logo
- Dashboard Navigation
- Games Navigation
- Logout Button
- Top Navigation
- Dashboard
- Total games played count
- Total Ping Pong games played
- Total Tic-Tac-Toe games played
- Total Rock-Paper-Scissors games played
- Graph displaying total games played per day over the last 7 days
- History of the last games played
- Leaderboard showcasing the top 10 players
- Refresh Button for updating dashboard statistics
- Live Chat
- Display list of active chats
- Interactive chat box
- Start Ping Pong game button
- Start Tic-Tac-Toe game button
- Start Rock-Paper-Scissors game button
- Delete conversation option
- Show basic user report
- Option to block a user
- Friends List
- Display user profile picture
- Show user name
- Show user gender
- Profile button
- Unfollow button
- Block user button
- Search Results
- Show total number of results found
- Display user profile picture
- Show user name
- Show user gender
- Profile button
- Follow/Unfollow button
- Block user button
- Profile
- Display user picture
- Show user name
- Show user ID
- Show user email
- Show user gender
- Display total games played
- Display total games won
- Display total games lost
- Show total Ping Pong games played
- Show total Tic-Tac-Toe games played
- Show total Rock-Paper-Scissors games played
- Display history of the last 20 games played
- Follow/Unfollow option
- Option to send a message
- Option to block the user
- Indicate if the user is online
- Settings
- Update profile picture
- Edit user name
- Change email address
- Reset or change password
- Link/UnLink google account
- Logged-in Sessions
- Display session name
- Sign out button for each session
- Sign out from all sessions button
- Two-Factor Authentication (2FA)
- Enable or disable 2FA
- Receive 2FA codes via email
- Use an authentication app for 2FA
- Blocked Users
- View blocked users list
- Unblock a user
- Account & Data Management
- Clear game history
- Permanently delete account
- Games
- Ping Pong
- Set user nickname
- Generate a unique game ID
- Generate a tournament game ID
- Enter game/tournament ID to join
- Join a random game button
- Tic-Tac-Toe
- Set user nickname
- Generate a unique game ID
- Generate a tournament game ID
- Enter game/tournament ID to join
- Join a random game button
- Rock-Paper-Scissors
- Set user nickname
- Generate a unique game ID
- Generate a tournament game ID
- Enter game/tournament ID to join
- Join a random game button
- Ping Pong
- Authentication
- Login
- Email input field
- Password input field
- "Remember Me" checkbox
- Password recovery link
- Submit button to log in
- Option to sign in with Google
- "Sign Up" button for new users
- Sign Up
- Full name input field
- Email input field
- Password input field
- Agree to terms & conditions checkbox
- Submit button to register
- Option to sign up with Google
- Two-Factor Authentication (2FA)
- Input field to enter authentication code
- "Verify" button to confirm identity
- Option to resend authentication code
- Account Recovery
- Input field for registered email
- "Recover Account" button
- Password Reset
- New password input field
- Confirm new password input field
- "Reset Password" button
- Login
- 404 Error Page
- Display "Page Not Found" message
- Show a friendly error description
- Include a home button to navigate back
- Responsive Design
- Support multiple screen sizes:
- Mobile (≤ 480px)
- Small Tablets (481px – 768px)
- Large Tablets (769px – 1024px)
- Laptops (1025px – 1366px)
- Desktops (1367px – 1920px)
- Ultra-Wide Screens (≥ 1921px)
- Check cross-browser compatibility for Chrome and Firefox
- Support multiple screen sizes:
- Forms Module Implementation
- Core Form Handling
- Specify
formId
to uniquely identify the form. - Define the HTTP request method (
GET
,POST
, etc.). - Set the target API endpoint for data submission.
- Specify
- Optional Callbacks
- Execute a function after a successful form submission (
onSuccess
).
- Execute a function after a successful form submission (
- Forms to handle
- Login Form
- Signup Form
- Account Recovery Form
- Password Reset Form
- Two-Factor Authentication (2FA) Form
- User Settings Form
- Core Form Handling
- User Data Module Implementation
- Core User Handling
- Process the API response object to manage user data.
- Handle session management with backend API
- Module Methods
- Data Retrieval
- Retrieve the user ID (
userId
) - Retrieve the user name (
userName
) - Retrieve the user email (
userEmail
)
- Retrieve the user ID (
- Session Management
- Fetch user data using session token (
fetchSessionData
) - Check authentication status (
isAuthenticated
) - Clear user data (
clear
)
- Fetch user data using session token (
- UI Integration
- Automatically update navigation bar user image
- Automatically update navigation bar user name
- Data Retrieval
- Core User Handling
- SPA Navigation Module Implementation
- Core User Handling
- Reference to the
userdata
object - Configure navigation elements (mainNav, sideNav, errorPage)
- Reference to the
- Module Methods
- Section Registration
- Add authenticated sections (
addDashSection
) - Add unauthenticated sections (
addAuthSection
) - Support optional FormHandler integration
- Support custom on-load functions with HTTP promise
- Handle URL path standardization (trailing slashes, query params)
- Add authenticated sections (
- Section Visibility
- Show/hide all sections (
hideAllSections
) - Dynamic section display based on auth state
- Active nav section highlighting
- Show/hide all sections (
- Error Handling
- Custom error page display (
showError
)
- Custom error page display (
- Browser History & Redirection
- Add a URL path to the browser history (
pushToHistory
) - Redirect the user to another URL path (
navigateTp
) - Page reload functionality (
reloadPage
)
- Add a URL path to the browser history (
- Event Handling for SPA Navigation
- Handle events for anchor (
<a>
) links - Initialize event listening on all anchor links for smooth SPA navigation
- Popstate event handling for back/forward
- DOMContentLoaded initialization
- Handle events for anchor (
- UI Integration
- Automatic user image/name updates
- Form state reset on navigation
- Section Registration
- Core User Handling
- Charts Module Implementation
- Core Initialization
- Specify the
elementId
of the DOM element that will contain the chart - Auto-detect system theme from localStorage
- Throw error for invalid element IDs
- Specify the
- Module Methods
- Chart Configuration – Getters
-
theme
: Get current chart theme ("light"|"dark") -
textColor
: Get current text color -
barColors
: Get array of bar colors -
categories
: Get x-axis categories -
dataSet
: Get chart data series
-
- Chart Configuration – Setters
-
setTheme
: Update chart theme -
setTextColor
: Update text color -
setBarColors
: Update bar colors array -
setCategories
: Update x-axis categories -
setDataSet
: Update chart data series
-
- Chart Rendering & Lifecycle
-
render()
: Create or update chart visualization- Auto-handles initial render and updates
- Listens for
themeChanged
custom events
-
destroy()
: Clean up chart instance- Removes event listeners
- Destroys ApexCharts instance
-
- Rendering & Lifecycle
- CSS variable support for colors
- Automatic conversion of CSS variables to computed values
- Fallback to #000000 for invalid variables
- Theme synchronization
- Reactive to system theme changes
- Dynamic re-rendering on theme updates
- CSS variable support for colors
- Chart Configuration – Getters
- Core Initialization
- Dashboard Module Implementation
- Core Initialization
- Requires base API endpoint and NavigationHandler instance
- Throws error if dashboard element not found
- Chart Configuration Proxy
- Getters
-
chartTextColor
: Get current chart text color -
chartBarColors
: Get array of chart bar colors -
chartTheme
: Get current chart theme ("light"|"dark")
-
- Setters
-
setChartTextColor
: Update chart text color -
setChartBarColors
: Update chart bar colors -
setChartTheme
: Update chart theme
-
- Getters
- Data Management
-
fetchStats()
: Retrieves stats from backend API- Handles network errors
- Manages credentials
-
load()
: Main loading method- Fetch website stats and update the DOM
- Returns HTTP promise
-
- UI Updaters
-
updateStatsCards()
: Updates all statistic cards -
updateProjection()
: Configures and renders chart -
updateLeaderBoard()
: Dynamically builds leaderboard- Creates ranked player list
- Generates profile links
- Loads player images
-
updateActivities()
: Renders game history- Adds game-specific icons
- Formats match results
- Displays timestamps
-
- Event Handling
- Automatic refresh button binding
- Chart cleanup on refresh
- Core Initialization
- Profile Loader Implementation
- Core Initialization
- Requires base API endpoint and NavigationHandler instance
- Throws error if profile element not found
- Chart Configuration Proxy
- Getters
-
chartTextColor
: Get current chart text color -
chartBarColors
: Get array of chart bar colors -
chartTheme
: Get current chart theme ("light"|"dark")
-
- Setters
-
setChartTextColor
: Update chart text color -
setChartBarColors
: Update chart bar colors -
setChartTheme
: Update chart theme
-
- Getters
- Data Management
-
fetchStats()
: Retrieves stats from backend API- Handles both current user and specified user profiles
- Manages URL parameter parsing (?id=)
- Handles network errors
- Manages credentials
-
load()
: Main loading method- Fetch profile stats and update the DOM
- Returns HTTP promise
-
- UI Updaters
-
updateProfileInfo()
: Updates user information- Handles profile picture
- Updates name, ID, and email
- Handle action buttons (block, unblock, accept...)
-
updateStats()
: Updates game statistics- Total games played
- Total games won
- Total games lost
-
updateProjection()
: Configures and renders chart- Shows games played per type
- Shows wins per game type
- Handles null data safely
-
updateActivities()
: Renders game history- Creates victory/defeat entries
- Adds game-specific icons
- Formats match results
- Displays timestamps
- Shows empty state when no history
-
- Core Initialization
- Theme Manager Implementation
- Core Initialization
- Optional theme button ID parameter (default: "mode-toggle")
- Automatic theme detection on instantiation
- Auto-binds click handler when button exists
- Theme Management
- State Getters
-
currentTheme
: Get active theme ("light"|"dark") -
getSystemTheme
: Detect OS-level preference -
getCachedTheme
: Retrieve stored preference
-
- State Setters
-
setTheme
: Programmatically set new theme- Persists to localStorage
- Triggers UI updates
- Broadcasts change event
-
-
toggleTheme()
: Switch between light/dark modes
- State Getters
- UI Synchronization
-
updateThemeButton()
: Dynamically updates toggle icon- Show sun icon for dark mode
- Show moon icon for light mode
-
updateWebSite()
: Applies theme globally- Sets
data-theme
attribute - Updates button state
- Broadcasts "themeChanged" event
- Sets
-
- Persistence
- Automatic localStorage management
- Falls back to system preference
- Validates stored values
- Core Initialization
- NavBar Handler Implementation
- Core Initialization
- Requires base API endpoint and NavigationHandler instance
- Element References
- Side navigation container
- Side nav toggle button
- Fullscreen toggle button
- Search Box
- Logout button
- Feature Implementation
- Side Navigation
- Toggle visibility with animation (
toggleSideNav
) - Handles width transition smoothly
- Manages hidden state
- Toggle visibility with animation (
- Fullscreen Management
- Toggle fullscreen mode (
toggleFullScreen
) - Cross-browser event support
- Dynamic button icon updates (
updateScreenButton
)
- Toggle fullscreen mode (
- Session Management
- Logout functionality (
logoutSession
) - Automatic redirect to login page
- Logout functionality (
- Search Functionality
- redirect to search page on submit
- Side Navigation
- Core Initialization
- Friends Loader Implementation
- Core Initialization
- Requires base API endpoint
- Throws error if friends element not found
- Sets up next/previous page button handlers
- Data Management
-
fetchStats()
: Retrieves friends results from backend API- Handles network errors
- Manages credentials
- Stores results and resets pagination
-
load()
: Main loading method- Fetches friends results and updates the DOM
- Returns HTTP promise
-
- UI Components
-
createItem()
: Generates user card element- Includes profile picture
- Shows username and online status
- Adds action buttons (block, unblock, accept...)
-
updatePageBody()
: Updates results display- Handles pagination calculations
- Creates user cards for current page
- Manages next/previous page boundaries
-
- Core Initialization
- Search Loader Implementation
- Core Initialization
- Requires base API endpoint
- Throws error if search elements not found
- Sets up next/previous page button handlers
- Data Management
-
fetchStats()
: Retrieves search results from backend API- Parses URL query parameter ("query")
- Handles network errors
- Manages credentials
- Stores results and resets pagination
-
load()
: Main loading method- Fetches search results and updates the DOM
- Returns HTTP promise
-
- UI Components
-
generateCountInfo()
: Displays total results count- Creates "X results found" message
- Clears previous results
-
createItem()
: Generates user card element- Includes profile picture
- Shows username and online status
- Adds action buttons (block, unblock, accept...)
-
updatePageBody()
: Updates results display- Handles pagination calculations
- Generates results count info
- Creates user cards for current page
- Manages next/previous page boundaries
-
- Core Initialization
To be added soon
- User Data
- Table Structure
-
id
→ INTEGER, PRIMARY KEY -
username
→ TEXT, UNIQUE -
email
→ TEXT, UNIQUE -
password
→ TEXT -
_2fa
→ BOOLEAN -
_2fa_method
→ TEXT (email
,app
) -
profile_visibility
→ TEXT (public
,friends_only
,private
) -
history_visibility
→ TEXT (public
,friends_only
,private
)
-
- Methods
- Create a new user
- Retrieve a user
- Retrieve all users
- Update user details
- Delete a user
- Table Structure
- Session Data
- Table Structure
-
token_id
→ TEXT, PRIMARY KEY -
user_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
ip_address
→ TEXT -
browser
→ TEXT -
platform
→ TEXT -
expiration_date
→ INTEGER (timestamp)
-
- Methods
- Create a new session
- Delete a session
- Delete all sessions for a user
- Retrieve a session by ID
- Retrieve all sessions for a user
- Validate a session
- Table Structure
- Friend Requests Data
- Table Structure
-
sender_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
recipient_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
status
→ TEXT (pending
,accepted
,blocked
)
-
- Methods
- Send a friend request
- Accept a friend request
- Reject a friend request (removes the row)
- Unfriend a user (removes the row)
- Retrieve a user's friends list (includes both pending and accepted)
- Retrieve all accepted friend requests for a user
- Retrieve all pending friend requests for a user
- Block a user
- Unblock a user (removes the row, same as rejection)
- Search for users (fetch from
Users
table, excluding blocked users)
- Table Structure
- Game History Data
- Table Structure
-
winner_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
winner_nickname
→ TEXT -
loser_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
loser_nickname
→ TEXT -
game_type
→ TEXT (ping-pong
,rock-paper
,tic-tac-toe
) -
date
→ INTEGER (timestamp)
-
- Methods
- Create a new game record
- Fetch game records for the website stats (
page_number
) - Fetch game records for a specific user (
user_id
,page_number
) - Fetch website leaderBoard
- Fetch website total records count
- Fetch website total records count for one day
- Fetch website records count for the last 7 days
- Fetch website dashboard statistics
- Fetch user total wins count (
user_id
) - Fetch user total loses count (
user_id
) - Fetch user Profile statistics (
user_id
)
- Table Structure
- Chat Data
- Table Structure
-
id
→ INTEGER, PRIMARY KEY -
user1_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
user2_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
)
-
- Methods
- Create a new chat
- Fetch all chats for a specific user
- Fetch chat by Participants
- Fetch chat by chat ID
- Fetch all chats
- Delete chat by chat ID
- Delete user from a chat
- Table Structure
- Messages Data
- Table Structure
-
chat_id
→ INTEGER, FOREIGN KEY (referencesChat.id
) -
sender_id
→ INTEGER, FOREIGN KEY (referencesUsers.id
) -
content
→ BLOB (message content) -
date
→ INTEGER (timestamp)
-
- Methods
- Send a message (
chat_id
,sender_id
,content
) - Fetch messages for a chat (
chat_id
,page_number
) – (20 messages per page)
- Send a message (
- Table Structure
-
/auth/signup POST
- Takes user data (
username
,email
,password
) - Validates all fields are present
- Checks if username/email already exists
- Creates new user if validation passes
- Returns appropriate success/error response
- Takes user data (
-
/auth/login POST
- Takes user credentials (
username
/email
andpassword
) - Verifies credentials match existing user
- Creates new session on success
- Sets authToken cookie on success
- Returns appropriate success/error response
- Takes user credentials (
-
/auth/recovery POST
- Takes user email as input
- Validates email format
- Checks if email exists in database
- Generates secure recovery serial
- Constructs recovery URL with (
user id
andserial
) - Sends recovery email containing the recovery URL
- Returns appropriate success/error response
- Returns success message even if email doesn't exist (security measure)
-
/auth/resetpass POST
- Takes (
userid
,serial
,password
, andconfirmPassword
) - Validates password confirmation matches
- Verifies serial is valid for recovery action
- Updates user password in database
- Creates new session on success
- Sets authToken cookie on success
- Returns appropriate success/error response
- Takes (
-
/auth/twofa POST
- Takes (
userid
,serial
,token
, andremember
) - Verifies user exists
- Validates 2FA token
- Verifies serial is valid
- Creates new session on success
- Sets authToken cookie on success
- Returns appropriate success/error response
- Takes (
-
/auth/verifyserial GET
- Takes (
id
: User ID) and (serial
) - Verifies serial is valid for user
- Returns appropriate success/error response
- Takes (
-
/auth/logout GET
- Checks for valid session cookie
- Deletes server-side session
- Clears the session cookie
- Returns appropriate success/error response
-
sessionData GET
- Checks for valid session cookie
- Returns current user's basic info if valid
- Returns error if session invalid/expired
-
picture/
:userId
GET- Takes target user ID in URL
- Verifies requesting user has valid session
- Returns profile picture if authorized
- Returns appropriate error if not found/blocked
-
stats GET
- Requires valid session
- Returns global website statistics
- Includes total games, game-type breakdowns
- Shows weekly trends and today's activity
- Returns recent match history
-
users/
:userId
GET- Takes target user ID in URL
- Verifies requesting user has valid session
- Checks if requesting user is blocked
- Returns target user's game statistics if authorized
- Shows win/loss records per game type
- Includes recent match history with opponents
- Returns appropriate error if not found/blocked
-
/search/
:query
GET- Takes search query in URL
- Returns users that match the search query
- Excludes blocked users
- Excludes users who blocked requester
- Returns appropriate success/error response
-
/friends GET
- Returns user friends data
- Returns appropriate success/error response
-
/relations POST
- Takes (
target
: Target user ID) and (action
) - Supported actions:
-
add
: Send friend request -
cancel
: Cancel sent request -
accept
: Accept friend request -
decline
: Decline friend request -
unfriend
: Remove friend -
block
: Block user -
unblock
: Unblock user
-
- Returns appropriate success/error response
- Takes (
- Pretect against Cross-Site Scripting (XSS) (implement after docker compose)
- Pretect against SQL Injection
- Implement a custom hashing algorithm
- Implement/Enforce HTTPS communication (implement after docker compose)
-
Oussama Kamili @oussamakami
-
Salah Eddine Lazar @slazar42
-
Abdellah amardoul @loudrama
-
Anas Kheireddine @kheireddine-anas
This Project Is Licensed Under © MIT