Skip to content

chutrunganh/Stock-Trading-Platform

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

103 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Banner

Typing SVG

A stock trading simulator built for beginners. Learn to trade without the risk.
Watch the demo video Β»

Features Β· Explore Docs Β· Request Bugs

Table of Contents
  1. Overview
  2. Features
  3. Installation & Setup
  4. Project Structure
  5. Security Checklist

πŸ“ Overview

Soict Stock Trading Platform is a full-stack web application that simulates a real-world stock trading environment. Designed for beginners and educational purposes, it allows users to practice trading stocks, manage portfolios, and learn about market dynamics in a safe, risk-free setting. Due to the limitations of the project scope, certain real-world trading rules and mechanisms have been simplified, see Stock Fundamental Theory section.

For security concerns, we have implemented some measures to mitigate common vulnerabilities and attacks. For more details, refer to the Security Checklist section.

πŸ› οΈ Technology Stack

The project is built with the following technologies:

Backend:

NodeJS Express Yarn PostgreSQL NodeMailer JSON Web Token Passport Sepay

Frontend:

React Vite Material UI Apex Charts

Deployment:

Docker Nginx Cloudflare

Security Testing:

Qodana OWASP ZAP

For more detailed explanations and implementations of the technologies used in this project, please refer to our Tech Stack.

πŸ“– Features

Note

Be patient! It may take a while (~2 minutes) to load all the demo gif images in this Features section.

⚑ Quick look ⚑:

Demo

Our application offers some key features:

  • User Authentication: Register or log in using email/username and password or using your Google account. Two-factor authentication (2FA) via OTP sent to your email is required on login. Optionally, you can select "Remember this device" to skip OTP next time. Includes "Forgot password" feature with OTP-based password reset.

    Login Demo

    Testing accounts: user1@stockmarket.com/ user1 with password Test@123 (for normal account) and admin@stockmarket.com/admin with password Test@123 (for admin account).

  • View Stock Board: Browse a real-time stock list with live price updates. Click on any stock to view detailed info, including price history shown in candlestick and line charts.

    Chart Demo
  • Tutorial: Step-by-step guide to help new users navigate the app and understand basic stock trading concepts.

    Tutorial Demo
  • Trading: Place buy/sell orders with support for both market and limit order types. You will get a notification on the home page when your order is matched.

    Trade Demo
  • Portfolio: Track your portfolio including available balance, estimated total value, the stocks you own, view transaction history, and add funds to your account.

    Portfolio Demo
  • Admin Page (for admin accounts only): Start or end a trading session.

    Admin Demo

For a live demo, you can watch our Demo Video.

Note

Some features of the website require third-party services such as Google SSO, Recaptcha with Cloudflare Turnstile, QR code banking payments via Sepay, and remote access through Cloudflare Tunnel. These services may become unavailable after the project is made public, as we plan to delete the associated accounts or projects for security and resource reasons. However, we provide detailed instructions 1 and detailed instructions 2 so you can reconfigure these services using your own keys or tokens.

(back to top)

πŸš€ Installation & Setup

Option 1: Using Docker

If you just want to quickly try out the app without diving into the code, we've got you covered with a docker-compose setup. Follow these steps:

  1. Download the docker-compose.prod.yml file only (no need to clone the project)
  2. Create a .env file in the same directory as the docker-compose production file, following the template in env.example, replace the values with your own credentials.
  3. Start Docker on your machine.
  4. Run the following command in the directory containing docker-compose.prod.yml:
docker-compose -f docker-compose.prod.yml up

This will pull the latest images for the backend, frontend, and database from Dockerhub then build and run them in containers.

The web will be available at:

Option 2: Building from Source

Note

Prerequisites: We assume that you have Node.js (version >= 22.14) and Yarn installed on your system.

If you're interested in exploring the code and running the project manually, follow these steps:

  1. Clone the repo and navigate to the project directory

     git clone https://github.com/chutrunganh/Stock-Trading-Platform.git
     cd Stock-Trading-Platform
  2. Set up environment variables

    Create a .env file in the project root by copying the template from .env.example, then fill in the required values by your own credentials.

  3. Set up the database

    You have two options:

    • Option 1: Install PostgreSQL application manually via their official website.

    • Option 2: Use our Docker setup to run only the database. In this case, you need to comment out our backend and frontend services inside the docker-compose file to run the database only.

    In both case, please recheck variables in the .env to make sure that:

    • DB_HOST is localhost, not postgres
    • BE_URL is http://localhost:3000, not a domain name
    • FE_URL is http://localhost:5173, not a domain name

    Then run docker-compose up to start the database.

    For detailed instructions on database setup, including configuration variables and solutions to common issues, we highly recommend taking a quick look at our Database Setup Guide and our Database Schemas

  4. Start the backend

    cd app/backend
    yarn install # Install dependencies
    yarn start
  5. Start the frontend

    cd app/frontend
    yarn install # Install dependencies
    yarn dev
  6. Open your browser and navigate to http://localhost:5173 to see the web in action.

Tip

When you start the backend, it will automatically connect to the database and seed some initial data. However, for stock prices, it only seeds data for one day, so the chart may not display fully as shown in the demo due to insufficient historical data. To populate the database with realistic stock prices, we provide a Python script that fetches real-world stock data and inserts it into the database. You can find the script in app/backend/src/utils/seedStockPrice. Please refer to this guide for instructions on how to run it.

Optional: Package the web with Docker 🐳

If you want to package the whole application (not just the database as above mentioned) with your source code changes to Docker images, use the docker-compose.yml file. First, check again the .env file, pay attention to these variables:

Variable Description Example Value
DB_HOST Must be set to postgres, not localhost postgres
BE_URL Backend URL. Use:
- http://localhost:3000 if running locally
- YOUR_DOMAIN_NAME if exposing via Cloudflare Tunnel
http://localhost:3000 or https://soictstock.io.vn
FE_URL Frontend URL. Use:
- http://localhost:5173 if running locally
- YOUR_DOMAIN_NAME if exposing via Cloudflare Tunnel
http://localhost:5173 or https://soictstock.io.vn

Note

Make sure FE_URL and BE_URL are set correspondingly, depending on whether you're running locally or using a public domain.

This will build the Docker images directly from the source code in the ./app/backend and ./app/frontend directories, which already contains the Dockerfile. This will run 4 services:

  • Backend
  • Frontend + Nginx as a proxy
  • Postgres SQL
  • Pgadmin

Access the webpage at: http://localhost:5173.

You can take an additional step to securely expose your Docker services to the internet using Cloudflare Tunnel (formerly Argo Tunnel). To do this, register a tunnel and link it to the domain name you specify in the BE_URL and FE_URL variables in your .env file. Then, follow the official instructions on the Cloudflare website to run the tunnel and make your services publicly accessible. The webpage now can be accessed via https://soictstock.io.vn. See instructions setup here.

πŸ—οΈ Project Structure

Overall Structure

πŸ“¦ Stock-Trading-Platform/
β”œβ”€β”€ πŸ“‚ app/
β”‚   β”œβ”€β”€ πŸ“‚ backend/        
β”‚   β”‚   β”œβ”€β”€ πŸ“‚ src/                     # Source code for the backend
β”‚   β”‚   β”œβ”€β”€ πŸ“„ package.json             # Backend dependencies
β”‚   β”‚   └── πŸ“„ Dockerfile               # Dockerfile for backend
β”‚   β”‚
β”‚   └── πŸ“‚ frontend/                   # Source code for the frontend
β”‚       β”œβ”€β”€ πŸ“‚ src/                    # Source code for the frontend
β”‚       β”œβ”€β”€ πŸ“„ package.json            # Frontend dependencies
β”‚       β”œβ”€β”€ πŸ“„ vite.config.js          # Vite configuration file
β”‚       β”œβ”€β”€ πŸ“„ nginx.conf              # Nginx configuration file
β”‚       └── πŸ“„ Dockerfile              # Dockerfile for frontend
β”‚
β”œβ”€β”€ πŸ“‚ docs/
β”‚   β”œβ”€β”€ πŸ“‚ design/                     # Detailed system design documents
β”‚   β”œβ”€β”€ πŸ“‚ reports/                    # Project reports
β”‚   β”œβ”€β”€ πŸ“‚ setupInstructions/          # Setup instructions for the project
β”‚   β”œβ”€β”€ πŸ“‚ techStack/                  # Technologies used, configuration guides
β”‚   └── πŸ“‚ stockFundamentalTheory/     # Financial terminology, order matching, etc.
β”‚
β”œβ”€β”€ πŸ“„ .env                            # Environment variables (not committed to GitHub)
β”œβ”€β”€ πŸ“„ .env.example                    # Example environment variables file (template)
└── πŸ“„ docker-compose.yml              # Run the whole app with Docker

For more details about the project structure, please refer to Project Architecture

Deployment Architecture

                            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                            β”‚    🌐 Public Internet      β”‚
                            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                         β”‚
                                         β–Ό
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚   🌩️ Cloudflare Proxy Edge  β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                       β”‚  (Tunnel)
                                       β–Ό
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚          πŸ–₯️ Local Machine (Docker Host)          β”‚
               β”‚  (All services isolated inside Docker network)   β”‚
               β”‚                                                  β”‚
               β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
               β”‚  β”‚  πŸ›‘οΈ cloudflared (Cloudflare Tunnel)      β”‚    β”‚
               β”‚  β”‚  - Forwards to frontend:5173 (Nginx)     β”‚    β”‚
               β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
               β”‚               β”‚                                  β”‚
               β”‚               β”‚                                  β”‚
               β”‚      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      β”‚
               β”‚      β”‚   frontend         β”‚                      β”‚
               β”‚      β”‚   (Nginx 5173:80)  β”‚                      β”‚
               β”‚      β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                      β”‚
               β”‚               β”‚                                  β”‚
               β”‚               β”‚                                  β”‚
               β”‚        β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
               β”‚        β”‚  backend         │────  postgres      β”‚ β”‚
               β”‚        β”‚(Node 3000:3000)  β”‚   β”‚  (DB 5432:5432)β”‚ β”‚
               β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
               β”‚                                      β”‚           β”‚
               β”‚                                β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”   β”‚
               β”‚                                β”‚  pgAdmin    β”‚   β”‚    
               β”‚                                β”‚ (UI 5050:80)β”‚   β”‚    
               β”‚                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚     
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Format: $HOST_PORT:$CONTAINER_PORT

(back to top)

πŸ” Security Checklist

Criteria Requirements Solution
1. Password Authentication 🟒 Enforce password policy Verified at both frontend and backend this policy:
  • Password length: 6–72 characters.
  • At least 1 uppercase letter, 1 number, and 1 special character (@$!%*?&)
  • Must not contain 3 or more consecutive characters from the username.
Refer to passwordUtils.js for implementations.
This password policy is a simplified version from VNDIRECT Securities JSC.
🟒 Secure password storage Use bcrypt for salting + slow hashing when storing passwords. Refer to userAuthService.js for implementations.
🟒 Prevention of password guessing Use CAPTCHA provided by Cloudflare Turnstile service to block spam/automated logins. Validate on both frontend and backend. Refer to turnstileService.js for implementations.
🟒 Password recovery Send OTPs to the user's email with expiration. For demo, we use Ethereal email. OTPs are 8 characters (mixed lower, upper case and numbers), expiry in 1 minute (testing only), generated with otp-generator dependency. Refer to otpService.js, userAuthService.js, AuthContext.jsx for implementations.
2. Session Authentication & Management 🟒 Secure mechanisms for using access tokens: prevention of tampering and guessing, expiration control Use JWT with short-lived Access Tokens (expiry in1 minute for testing) and longer-lived Refresh Tokens (expiry in 7 days). Tokens include a timestamp in the payload before signing to ensure uniqueness on every login. Return tokens to the client via cookies with the following security attributes:
  • Secure (enabled in production only)
  • HttpOnly
  • SameSite='Strict'
On logout or browser close, clear all cookies on the client and revoke the Refresh Token on the server. Refer to jwtUtil.js, setCookieUtil.js, authenticationMiddleware.js, AuthContext.jsx for implementations.
🟒 CSRF defense
  • Only allow requests from the frontend origin using: (in the index.js )
    app.use(cors({
      origin: process.env.FE_URL}));
    We do not provide public API.
  • Cookies with SameSite='Strict' property.
🟒 Session hijacking defense Using tokens with cookies as mentioned above
3. Authorization 🟒 Implement suitable access control: MAC, DAC, RBAC Implemented Role-Based Access Control (RBAC) with permission matrix:

    const ROLE_PERMISSIONS = {
      [ROLE_HIERARCHY.ADMIN]: {
        canAccessAdminDashboard: true,
        canControlTradingSession: true
      },
      [ROLE_HIERARCHY.USER]: {
        canAccessAdminDashboard: false,
        canControlTradingSession: false
      }
    };
    
The application currently supports two roles: user and admin.
  • Public guests: Can access Home and Tutorial pages.
  • Logged-in users: Can additionally access Trade and Portfolio pages.
  • Admins: Can additionally access Admin page.
Refer to roleBasedAccessControlMiddleware.js for implementations.
4. Input Validation & Output Sanitization 🟒 Input validation and sanitization User input is validated and sanitized using middleware located in userValidationMiddleware.js (used for login, registration, and password reset forms), orderMiddleware.js, and tradingSessionMiddleware.js (used for enforcing order constraints).

Response data is filtered using responseSanitizationMiddleware.js and errorHandlerMiddleware.js.

We use the joi and xss libraries for input and output sanitization. In addition, a Content Security Policy (CSP) is configured to restrict the types of resources the browser can load.
🟒 Protection against injection attacks
  • Use parameterized queries with placeholders like $1 for SQL to prevent injections. See in userCRUDService.js for an SQL query example.
  • Config CSP (Content Security Policy) with helmet dependency to limit resource that browser can load, see in index.js.
🟑 Prevention of path traversal Prevent IDOR (Insecure Direct Object Reference) by :
  • Using UUID instead of auto-incrementing ID for primary key in sensitive database tables (See the userModel.js and portfolioModel.js).
  • With routes that need to query by ID, extract the userID/portfolioID from the JWT, we do not accept it from the request parameters. See in portfolioController.js, orderController.js as some examples. However this is not fully implemented for all needed routes yet.
  • For routes that not allow to access (require authentication or authorization) return this 404 page.
🟒 File upload restriction No file upload functionality in current app version so no need to implement this
5. Sensitive Information Leakage 🟑 Minimization of sensitive information leakage about servers, software, and applications Check out our nginx.conf file for more details on security headers and configurations to minimize information leakage.
🟒 Minimization of sensitive information leakage in response Disable X-Powered-By in HTTP response header through using helmet dependency. This header is set by default in Express and some other frameworks to reveals which framework the server is using, which can aid attackers during reconnaissance
🟒 Mitigate Clickjacking Set X-Frame-Options: DENY in HTTP response header through using helmet dependency to prevent website to be embedded into other sites using iframe tag
6. Compliance with Standards 🟒 HTTPS implementation Use Cloudflare Tunnels to public web service and get free SSL
🟑 Mitigation of DoS attacks Requests pass through Cloudflare proxy when using Cloudflare Tunnel. Configure rate-limiting, geography-based IP rule, block specified user agents on Cloudflare WAF (Web Application Firewall), see WAF_1 and WAF_2. However, we just enable and use prebuild rules template without any research, customization or testing these settings yet.
🟒 Secure storage and management of sensitive values Use an environment variables file named .env to store secret values and keys. All parts of the source code that need these values must load them from this file instead of hardcoding them. The .env file is not committed to GitHub. Instead, we provide a .env.example file as a template to help you recreate your own .env file with your credentials.
7. Security Testing 🟒 Code review with automated tools Scan with Qodana from Jetbrains. All Critical, High level warnings have been fixed, still some Moderate warnings left.
🟒 Penetration testing with tools Using ZAP Proxy. No High level alerts, only alerts at Medium, Low and Informational level left.
8. Bonus 🟒 Multi-factor authentication After entering correct username/email and password, OTP is sent to user's email. OTP must be valid and unexpired. We also have "Remember device in ... time" implemented to skip OTP next time login. Devices are identified by using fingerprintJS dependency (free version). See in otp service (for otp implementation) and LoginForm.jsx (for device fingerprint identification).
πŸ”΄ Advanced session hijacking prevention Track user IPs, detect unfamiliar devices/browsers.
🟑 Advanced HTTP flood prevention Configure the Cloudflare WAF for the domain.
🟒 Single Sign-On (SSO) Implemented Google OAuth 2.0 using passport dependency, see in passportConfig.js and userAuthService.js.

Status Explanation:

  • 🟒 Done: Mitigation measures have been implemented to the best of our knowledge. (Note: This does not guarantee complete immunity from the attack.)

  • 🟑 Partially Done / Not Applicable: The measures are either just proposed ideas, partially implemented, and have not been fully tested or validated yet.

  • πŸ”΄ Not Implemented: No mitigation has been applied yet.

(back to top)

Code review with Qodana

Code review

All warnings at Critical, High level have been fixed. There are still some Medium level warnings left we cannot fix yet due to time constraints.

Code penetration testing with OWASP ZAP

Code penetration testing

No alerts at High level, only alerts at Medium, Low and Informational level left.

(back to top)

🀝 Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

For the success of this project, I want a special thanks to:

  • Project supervisor: MSc. BΓΉi Trọng TΓΉng, Dr. Đỗ BΓ‘ LΓ’m

  • Team members:

    Name Student ID
    Chu Trung Anh (team leader) 20225564
    BΓΉi Duy Anh 20225563
    PhαΊ‘m MαΊ‘nh TiαΊΏn 20225555

πŸ“œ License

License: Apache-2.0

Distributed under the Apache-2.0 License License. See LICENSE for more information.

πŸ“§ Contact

This project is maintained by: Chu Trung Anh - Email.

Feel free to contact me if you have any questions or suggestions.

(back to top)

About

πŸ“ˆ A secure, full-stack stock trading simulator platform for beginners, built with Node.js, PostgreSQL, and React as part of the IT4403E course at HUST (20242)

Topics

Resources

License

Stars

Watchers

Forks

Contributors