This is the backend server that powers the RouteSync transport management platform. It is built with Node.js and Express.js. Think of it as the brain of the entire system β it handles all the important tasks like storing data, checking user permissions, managing bus routes, processing transport card applications, and keeping track of payments.
The backend uses PostgreSQL (a powerful database) to store all information securely. It also uses Firebase Admin SDK to verify that every request comes from a real, logged-in user. This means no one can cheat the system or access data they shouldn't see.
| Layer | Technology |
|---|---|
| Runtime | Node.js |
| Framework | Express.js |
| Database | PostgreSQL (via postgres.js) |
| Security/Auth | Firebase Admin SDK, JWT Verification |
| Middleware | CORS, Express.json(), Custom Token Validator |
The backend uses a relational database, which means data is stored in different tables that connect to each other. Think of it like filing cabinets β each cabinet (table) holds one type of information, and they are linked together with ID numbers.
Here are the four main tables:
- Stores basic information for every person who signs up
- Contains:
name(full name),email(login email), androle(what type of user they are) - Role can be:
admin(full control),student(verified student), ornon-student(registered but not verified) - Every user gets a unique ID number
- Connected to the
userstable usinguser_id(like linking two files together) - Stores university-specific information that regular users don't have
- Contains:
student_id(university ID number),department(e.g., Computer Science),edu_mail(university email), andcard_status(does this student have an active transport card?) - A person can only have a student record if they have verified their university status
- Connected to the
studenttable usingstudent_id - This table keeps a record every time a student applies for a transport card
- Contains:
paid_amount(how much money they paid), application date - This helps track who has applied and whether an admin has approved them
- This is a standalone table (not directly connected to users)
- Stores every bus route in the system
- Contains: origin (starting point), destination (ending point), timings (when the bus runs), price (how much it costs), and
stops_str(a comma-separated list of all stops in between) - Example of
stops_str:"Main Gate,Library,Science Building,North Hall"
βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββ
β users β β student β β card_apply β β bus_routes β
βββββββββββββββββββββββ€ βββββββββββββββββββββββ€ βββββββββββββββββββββββ€ βββββββββββββββββββββββ€
β π id (PK) β β π id (PK) β β π id (PK) β β π id (PK) β
β name β β π user_id (FK) β β π student_id (FK) β β origin β
β email β β student_id β β paid_amount β β destination β
β role β β department β β apply_date β β timings β
β β β edu_mail β β β β price β
β β β card_status β β β β stops_str β
ββββββββββββ¬βββββββββββ ββββββββββββ¬βββββββββββ ββββββββββββ¬βββββββββββ βββββββββββββββββββββββ
β β β_______
β ____ | |
βΌ (1-to-1) βΌ (One-to-Many) |
users.id βββββββΊ student.user_id student.id βββββββΊ card_apply.student_id bus_routes (Standalone)
users table:
βββββββ¬βββββββββββ¬ββββββββββββββββββββββ¬ββββββββββ
β id β name β email β role β
βββββββΌβββββββββββΌββββββββββββββββββββββΌββββββββββ€
β 101 β John β john@university.edu β student β
βββββββ΄βββββββββββ΄ββββββββββββββββββββββ΄ββββββββββ
β
β (One-to-One)
βΌ
student table:
ββββββ¬ββββββββββ¬βββββββββββββ¬βββββββββββββββ¬βββββββββββββ
β id β user_id β student_id β department β card_statusβ
ββββββΌββββββββββΌβββββββββββββΌβββββββββββββββΌβββββββββββββ€
β 5 β 101 β CS2024001 β CS β pending β
ββββββ΄ββββββββββ΄βββββββββββββ΄βββββββββββββββ΄βββββββββββββ
β
β (One-to-Many)
βΌ
card_apply table:
ββββββ¬βββββββββββββ¬ββββββββββββββ¬βββββββββββββββββββββ¬
β id β student_id β paid_amount β apply_date β
ββββββΌβββββββββββββΌββββββββββββββΌβββββββββββββββββββββΌ
β 1 β 5 β 50.00 β 2024-01-15 β
β 2 β 5 β 50.00 β 2024-02-20 β
ββββββ΄βββββββββββββ΄ββββββββββββββ΄βββββββββββββββββββββ΄
Every time the frontend (React app) wants to get or send data, it must prove that the user is logged in. Here's how it works:
- When a user logs in through the frontend, Firebase gives them a special token (like a digital ID card)
- The frontend attaches this token to every request it sends to the backend
- The backend has a special function called
fireBaseTokenVarify(like a security guard at a gate) - This security guard:
- Checks if the token exists
- Uses Firebase Admin SDK to verify the token is real and not expired
- Extracts the user's email from the token
- Attaches the email to the request so other parts of the code know who is asking
- If the token is missing or fake, the backend immediately returns a 401 Unauthorized error
- The user sees "Please log in again" or is redirected to the login page
Why this matters: Without this, anyone could pretend to be an admin and delete bus routes or approve fake card applications. This security layer protects the entire system.
When a student searches for a bus from "Main Gate" to "Science Building", the backend doesn't just look for those words. It does something much smarter:
Step 1: Find Matching Buses
- The backend queries the database using PostgreSQL's
ILIKEoperator (which ignores uppercase/lowercase differences) - It looks for any bus route that contains both the "From" location and the "To" location somewhere in its stops list
Step 2: Check Direction (This is the Smart Part)
- Just because a bus passes through both stops doesn't mean it goes in the right direction
- Example: A bus might go: "North Hall β Library β Main Gate β Science Building"
- If you want to go from "Main Gate" to "Science Building", that's fine (Main Gate comes before Science Building)
- But if you want to go from "Science Building" to "Main Gate", the bus would be going backward
- The backend checks the index position (order number) of each stop in the
stops_str - It makes sure the "From" stop index is less than (comes before) the "To" stop index
- If the "From" comes after the "To", that bus is not shown in results
Why this matters: This prevents showing students buses that would take them in the wrong direction, even if the bus passes through both locations.
When a student applies for a transport card, it's not as simple as just saving one piece of information. The backend must update multiple tables in a single action. Here's what happens in one API call:
What the backend does automatically:
-
Creates a payment record in the
card_applytable- Records how much the student paid
- Records the date and time of application
- Sets initial status to
pending
-
Updates the student's information in the
studenttable- Stores their current semester (e.g., "Fall 2024")
- Updates their department if changed
- Sets their
card_statustopending(waiting for admin approval)
-
Syncs the user's name in the
userstable- Ensures the full name is correct everywhere
- This prevents display issues on the frontend
Why this matters: If any of these steps fail (e.g., database connection drops), the entire request fails and nothing is saved. This is called a "transaction" β all or nothing. This prevents partial data (like a payment record with no student attached) from corrupting the system.
| Method | Route | Description | Who Can Use |
|---|---|---|---|
GET |
/users |
Get all registered users (or search by email) | Only logged-in users |
POST |
/users |
Register a new user in the database | Anyone (signup) |
POST |
/student |
Add university information to a user account | Logged-in users |
GET |
/studentinfo |
Get combined user info + student info (like a merged report) | Logged-in users |
| Method | Route | Description | Who Can Use |
|---|---|---|---|
GET |
/schedule |
Search for buses by location and day | Anyone (even without login) |
GET |
/manage-busses |
Get all buses (for admin dashboard) | Only admins |
GET |
/busses/:id |
Get details of one specific bus by its ID | Only logged-in users |
POST |
/bus-routes |
Add a new bus to the system | Only admins |
PATCH |
/bus-routes/:id |
Update an existing bus route | Only admins |
DELETE |
/bus-routes/:id |
Remove a bus route completely | Only admins |
| Method | Route | Description | Who Can Use |
|---|---|---|---|
POST |
/apply-transport-card |
Submit an application for a transport card | Only verified students |
GET |
/card-applications |
View all card applications (pending and active) | Only admins |
PATCH |
/card-status/:id |
Approve or reject a student's card | Only admins |
GET |
/payments |
View all payment transaction history | Only admins |
GET |
/payment-stats |
Get total revenue (dashboard numbers) | Only admins |
| Method | Route | Description | Who Can Use |
|---|---|---|---|
GET |
/admin/students |
Get all students with their complete information (combines multiple tables) | Only admins |
PATCH |
/admin/users/promote/:id |
Change a regular user into an admin | Only admins |
PATCH |
/admin/users/revoke/:id |
Remove admin access from someone | Only admins |
DELETE |
/admin/users/:id |
Permanently delete a user and all their student records | Only admins |
This guide explains how to install, configure, and run the backend server locally, along with an overview of required dependencies.
Download the backend source code and navigate into the project directory:
git clone https://github.com/Riad-Zz/DIU_TranSit_Server.git
cd DIU_TranSit_ServerInstall all required packages:
npm installThis will download all necessary libraries such as Express, PostgreSQL client, Firebase Admin SDK, and others required for the backend to function.
Create a .env file in the root directory and add the following:
PORT=3000
DATABASE_URL=postgres://user:password@host:port/dbname
FIREBASE_KEY=your_base64_encoded_service_account_json- Go to Firebase Console
- Open Project Settings β Service Accounts
- Click Generate New Private Key
- Download the JSON file
- Convert the JSON file into a Base64 string
- Paste the encoded string as the value of
FIREBASE_KEY
Why Base64? The Firebase service account file contains line breaks and special characters. Encoding it ensures it can be safely stored in a single-line environment variable.
npx nodemon index.jsnode index.jsIf configured correctly, the server will start with:
Server running on port 3000
{
"cors": "^2.8.5",
"dotenv": "^16.x.x",
"express": "^4.x.x",
"firebase-admin": "^12.x.x",
"postgres": "^3.x.x"
}-
cors Enables communication between frontend and backend across different origins
-
dotenv Loads environment variables from
.env -
express Handles routing and server logic
-
firebase-admin Verifies authentication tokens and interacts with Firebase services
-
postgres Connects to PostgreSQL and executes database queries
{
"nodemon": "^3.x.x"
}- nodemon Automatically restarts the server during development when file changes are detected