Wheesh is a prototype website designed to help people simulate the process of booking train tickets online. There are 10 features:
- Registration and Login
- Profile Management
- Account Security (Change Email, Change Password)
- Manage My Passengers
- Banner Management (By Admin)
- Schedule
- Ticketing (Booking Ticket, Pay Order (not implementing payment gateway), Cancel Order)
- See Orders (Unpaid Orders, Paid Orders, History Orders)
- QR Validation
The QR Validation is onGate
page - Reminder
Remind user about one hour before departure via email
This project supports server creation in two languages: JavaScript using the Express framework and Java using the Spring Boot framework. For demonstration purposes, the Java implementation is showcased here.
You can view the demo here.
- Setup
.env
fileVITE_API_HOST=<SERVERL_URL_API> // Remember to add "/api" at the back VITE_CRYPTO_KEY= // This is okay if empty (it should be deleted)
- Install the dependencies
npm i
npm start
npm run test
- Express
Click this link to read the API Documentation - Spring Boot
It's almost the same with the Express one.
For detailed information about the client routes, please refer to the Client Routes README.
Summary of what the stack looks like on each side:
Tech stacks:
- express, framework that helps developing backend (or server)
- sequelize, an ORM (Object Relational Mapping)
- mysql2, helps connecting sequelize with MySQL driver
- jsonwebtoken, helps creating token and validating token for authentication
- bcryptjs, helps hashing and check the password is the same with hash password
- joi, helps validating the request body's structure and some special conditions (e.g. validate format of
ID Card
) - cors, helps enabling CORS on backend
- multer, handle uploading files from client
- nodemon, helps developing backend (by restart the server when the codes are changed)
- jest, help testing in Javascript
- supertest, help testing HTTP requests
- dotenv, help storing sensitive information without hardcoding them directly into source codes
- ioredis, do the caching
- ioredis-mock, mock the
ioredis
when testing - nodemailer, help sending email
- node-cron, automate some jobs in periodic time
Tech stacks:
- React, framework for creating user interfaces
- react-dom, serves as the entry point to the DOM and server renderers for React
- react-router-dom, contains bindings for using React Router in web applications
- react-responsive, helps coding media query inside Javascript codes
- react-hot-toast, helps notificating user on user interfaces
- vite, helps faster developing / coding on frontend
- sass, helps custom styling
- Material UI, helps styling
- classnames, helps styling
- Redux, helps state management (to reduce number of passing
props
)- react-redux, helps implementing
redux
inReact
app - redux-saga, do the side effects of redux (e.g. fetching data)
- redux-persist, helps storing some states of
reducer
in local storage
- react-redux, helps implementing
- lodash, helps delivering modularity in Javascript
- immer, helps changing state in
reducer
(by usingproduce
method) - reselect, helps data handling (
createSelector
on allselectors.js
andcreateStructuredSelector
on allindex.jsx
) - react-intl, helps internationalize React applications
- jest, helps testing in Javascript
- prettier, helps tidying up the source codes
- eslint, helps identifying and reporting on patterns found in ECMAScript/JavaScript code
- axios, helps making HTTP requests
- swiper, helps making carousel of banners
- qrcode, helps generating QR code
- html5-qrcode, helps scanning QR code on user interface
When a user opens a page, certain pages necessitate fetching data from the server initially. The page triggers an action
bound to a constant
—all variables in constants.js
specific to each page—to execute the corresponding method in the saga
for the required logic. The saga
method, in turn, invokes the corresponding method in the domain API to send an HTTP request to the server for data retrieval. Upon receiving the response, the domain API sends it back to the saga
method, which, in turn, triggers another action
to update the reducer
's state
within the store
. Consequently, the page reflects the fetched data through its updated state
.
Similarly, when a user initiates a create, update, or delete operation, the page again triggers an action
to execute the corresponding logic in the saga
. This saga
method, similar to the data fetching scenario, calls the relevant method in the domain API to send an HTTP request for creating, updating, or deleting something on the server. The domain API, upon receiving a response, sends it back to the saga
method. Subsequently, the saga
method triggers an additional action
to modify the reducer
's state
within the store
. The page then reflects the updated state
accordingly.
When a request is sent to the server, it follows a specific route. Some routes directly invoke a method within the controller
, while others pass through various middlewares before reaching a method inside the controller
. For instance, when a client requests profile data via the /api/user
endpoint, the request is initially directed to the authentication
middleware to verify the presence and validity of an authorization token. If the request fails within the authentication
middleware, a BAD REQUEST
response is sent to the client. Otherwise, the request proceeds to the specified method within the controller. Within these controller methods, distinct logic is implemented for various purposes. For example, on the /api/user
endpoint, the method might execute a query using sequelize
's Model
to retrieve user data and subsequently send a response containing the profile data to the client. Additionally, some controller methods utilize utility methods for specific logic, such as hashing passwords or creating authorization tokens.
The node-cron
module consistently executes its tasks periodically. These tasks typically involve querying the database and potentially updating its contents. For instance, the deleteNotPaidOrderPassedDueTime
job is responsible for removing unpaid orders that have exceeded their due time. If certain conditions are met, this job will delete the corresponding order from the database.