Welcome to the server-side repository of the Professional Mountain Biking Coaching Network website. This backend powers the API, database, authentication, transactional emails, and all server-side logic for the platform.
- π Features
- π§° Packages & Technologies Used
- π Project Structure
- β Prerequisites
- π§ Installation, Configuration & Running Locally
- π‘ API Endpoints
- π§ͺ Testing the API
- π¨ Email System
- π Demo Data Freshness
- π» Checkout the Client End
- π Live Deployment
- π’ Uptime Monitoring
- π€ Contributing
- π License
- RESTful CRUD operations for users, instructors, classes, and bookings
- MongoDB database integration for persistent data storage
- Environment-based configuration for secure deployment
- Search, filter, and sort for instructors and courses
- Transactional emails (enrollment, payment receipts) via Nodemailer & Mailgun
- Date and time formatting with Moment.js
- Handlebars for dynamic HTML email templates
- Automated and manual endpoints for demo data freshness (see below)
Full list of Packages & Technologies Used (Click to expand)
- Node.js: JavaScript runtime for building scalable server-side applications
- Express.js: Fast and minimalist web framework for Node.js
- MongoDB: NoSQL database used for storing application data
- Moment.js: Utility for formatting and manipulating dates
- Nodemailer: Library for sending emails from the server
- Mailgun: Email API service used as a transport for Nodemailer
- Handlebars: Templating engine for formatting dynamic HTML email bodies
- Render: Cloud platform for deploying and hosting the backend server
- UptimeRobot: Monitoring tool to ensure the backend is always up and running
MTB-Coaching-Server/
βββ public/ # Static assets (images, logos, etc.)
βββ src/
β βββ routes/ # API route handlers
β β βββ bookings.js # Booking and payment-related endpoints
β β βββ classes.js # Class-related endpoints
β β βββ instructors.js # Instructor-related endpoints
β β βββ users.js # User-related endpoints
β βββ app.js # Express app configuration
β βββ email.service.js # Email sending logic
β βββ server.js # Server startup and environment config
βββ scripts/
β βββ updateClassDate.js # Script to randomize instructor class dates for demo freshness
βββ templates/
β βββ paymentConfirmation.html # HTML template for payment confirmation emails
βββ .env.example # Example environment variables
βββ .gitignore # Git ignored files
βββ LICENSE # MIT license
βββ package-lock.json # NPM lockfile
βββ package.json # Project metadata and dependencies
βββ README.md # Project documentation (this file)
- Node.js (v18 or higher recommended)
- npm (comes with Node.js)
- MongoDB (Atlas or local instance)
- A
.envfile with required environment variables
-
Clone the repository:
git clone https://github.com/Tanzeebul-Tamim/MTB-Coaching-Server cd MTB-Coaching-Server -
Install dependencies:
npm install
-
Set up Environment Variables:
-
Rename the
.env.examplefile in the project root to.envand fill in your credentials:PORT=5000 DB_USER=yourDatabaseUser DB_PASS=yourSecureDbPassword PAYMENT_SECRET_KEY=sk_test_YourPaymentSecretKeyHere EMAIL_PRIVATE_KEY=yourEmailPrivateKey EMAIL_DOMAIN=mg.yourdomain.com MAIL_SENDER=verified_sender@example.com ADMIN_SECRET=your_admin_secret_here
-
Guide & Configuration Details (Click to expand)
-
PORT(Server Port):The port your server will listen on (commonly
5000or8000). -
DB_USER(Database Username):Username credential for your database (used in connection string or DB config).
-
DB_PASS(Database Password):Corresponding password for the
DB_USER. -
PAYMENT_SECRET_KEY(Payment Gateway Secret Key):Your Stripe payment processorβs private/secret key .
-
EMAIL_PRIVATE_KEY(Email Private Key):The private key from your Nodemailer email service provider.
-
EMAIL_DOMAIN(Email Domain):Domain or subdomain configured for sending emails.
-
MAIL_SENDER(Sender Email Address):The verified sender address used by your mailer - Nodemailer to send emails from the application. This email must be authorized in your email service configuration.
π Note: In development, you can use a test email. In production, make sure this is a verified and authenticated sender (especially for services like Mailgun, SendGrid, etc.).
-
β οΈ Caution:
Never commit your.envfile to version control (GitHub, Git, etc.) as it contains sensitive credentials. Always keep this file private and add.envto your.gitignore. -
-
Start the server:
npm start
Easily integrate with the MTB Coaching Network backend using these RESTful API endpoints.
β NB:
Several endpoints require query or request body parameters for correct operation. If you do not provide the required parameters, you may receive empty results or errors.
Click to expand for a full list of available API endpoints and usage examples
-
Users
-
PUT
/users/:email:Save or update a user in the database. Expects user data in the request body.
Required Request Body Parameters:
name(string): Full name of the user.role(string): User's role in the system, such asstudentorinstructor
Example:
PUT/users/john@example.comBody:
{ "name": "John Doe", "role": "Student" } -
GET
/users/:email:Get a specific user by email.
Example:
GET/users/john@example.com
-
-
Instructors
-
GET
/instructors?count=<number>&search=<string>:Get a list of all instructors.
Optional query parameters:count(number): Limits the number of instructors returned. If omitted, returns all.search(string): Case-insensitive search by instructor name. If omitted, returns all.
Example:
GET/instructors?count=5&search=Alex -
GET
/instructors/total:Get the total number of instructor accounts registered.
-
GET
/instructors/top:Get the top 6 instructors (by total students) and a list of all instructors with their total students.
-
GET
/instructor/total/:id:Get the number of total students of a specific instructor.
Example:
GET/instructor/total/6653e1b2c1a2b3d4e5f6a7b8 -
GET
/instructor/students/:id/:idx:Get the student list of a specific course of a specific instructor (
idxrepresents course-index).Example:
GET/instructor/students/6653e1b2c1a2b3d4e5f6a7b8/0 -
GET
/instructor/:id:Get a single instructor by MongoDB ObjectId.
Example:
GET/instructor/6653e1b2c1a2b3d4e5f6a7b8 -
PUT
/instructor/updateStudentCount:Update an instructor's class student count.
Required Request Body Parameters:
instructorId(string): The unique identifier of the instructor.classIndex(number): The index of the class to update.
Example:
PUT/instructor/updateStudentCountBody:
{ "instructorId": "6653e1b2c1a2b3d4e5f6a7b8", "classIndex": 0 }
-
-
Classes
-
GET
/classes/total:Get the total number of classes.
-
GET
/classes/top:Get the top 6 classes (by total students).
-
GET
/classes?count=<number>&search=<string>:Get all classes.
Query parameters:
count(number): Limits the number of classes returned. If omitted, returns empty array.search(string): Case-insensitive search, filters by class name. If omitted, returns all.
π Note:
countis required &searchis optional.Examples:
GET/classes?count=10
GET/classes?count=5&search=Beginner
-
-
Bookings
-
PUT
/book-class:Post a booking. Expects booking details in the request body.
Required Request Body Parameters:
studentId(string): The unique identifier of the student.instructorId(string): The unique identifier of the instructor.studentEmail(string): Email address of the student.studentName(string): Name of the student.classIndex(number): The index of the class to update.paymentStatus(string): ndicates whether the student has completed payment (paidorunpaid).transactionId(string): The unique Stripe transaction ID associated with the payment.date(string): Timestamp of the payment, stored as an ISO date string in MongoDB.
Example:
PUT/book-classBody:
{ "classIndex": 1, "instructorId": "664fd275e708c848f468d0cd", "studentId": "8b1bba74f6764dd8a92a1111", "date": "2023-06-02T01:50:00.000Z", "paymentStatus": "paid", "studentEmail": "kunderwood@yahoo.com", "studentName": "James Aguilar", "transactionId": "pi_Nc9zs7Xqr6LXS9W7aCgRr4Uz" } -
GET
/book-class/:studentId:Get all bookings for a user by their studentId.
Example:
GET/book-class/6653e1b2c1a2b3d4e5f6a7b8 -
GET
/book-class/:loggedId/:studentId/:itemId:Get a specific booking by studentId and booking itemId.
β οΈ Security Note:
TheloggedIdparameter represents the currently logged-in user's ID. The server comparesloggedIdwithstudentIdto ensure that users can only access their own bookings. If the IDs do not match, access is denied. This mechanism prevents users from viewing or manipulating bookings that do not belong to them, enforcing user-level access control.Example:
GET/book-class/6653e1b2c1a2b3d4e5f6a7b8/6653e1b2c1a2b3d4e5f6a7b8/6653e1b2c1a2b3d4e5f6a7c0 -
DELETE
/book-class/:studentId:Delete a specific booking by studentId and itemId.
Required Request Body Parameters:
instructorId(string): The unique identifier of the instructor.classIndex(number): The index of the class to update.
Example:
DELETE/book-class/6653e1b2c1a2b3d4e5f6a7b8Body:
{ "instructorId": "6653e1b2c1a2b3d4e5f6a7b8", "classIndex": 0 } -
DELETE
/booking/:studentId:Delete all unpaid bookings for a user by studentId.
Example:
DELETE/booking/6653e1b2c1a2b3d4e5f6a7b8 -
POST
/create-payment-intent:Create a Stripe payment intent. Expects
{ price }in the request body.Required Request Body Parameters:
price(number): The amount to be charged for the payment intent.
Example:
POST/create-payment-intentBody:
{ "price": 99.99 }
-
- Use Postman, Insomnia, or your browser (for GET requests) to test endpoints.
- For endpoints requiring query parameters, always include them in the URL.
- For
POST/PUTendpoints, provide the required JSON body. - The server responds with JSON data for all endpoints.
β NB: For more details on request/response formats, see the source code in
src/routes/.
This server uses Nodemailer with Mailgun and Handlebars templating to send transactional emails, such as:
- Enrollment confirmations
- Payment receipts
β οΈ Note on Email Testing:
Due to the use of a Mailgun sandbox domain (part of the free-tier setup), emails can only be sent to pre-authorized recipients. This means only specified test addresses (e.g., mine) will successfully receive emails. Other users will not receive them unless added as authorized recipients.
To evaluate the email system:
- Review the email logic, template, and integration in the source code.
- See the screenshot below for a sample rendered email:
To keep the course list always fresh (so courses don't all end up as "ended" after a while), the backend provides a way to randomize instructor class dates:
- Procedure: Run
scripts/updateClassDate.jsmanually or runnpm run refreshto randomize all instructor class dates in the database. This simulates a real, active site with a mix of "ongoing", "upcoming", and "ended" courses. - Purpose: Ensures the UI always displays a realistic mix of course statuses for demo/testing.
Visit the front-end repository of the website.
The API is deployed on Render and can be accessed at this URL.
β οΈ Note on Free Hosting (Render):
The backend is hosted on Renderβs free plan. The server will βspin downβ after inactivity, so the first request after a while may take up to 50 seconds to respond. Subsequent requests will be fast. This is normal for free-tier hosting.
The serverβs uptime is monitored by UptimeRobot. View real-time status here.
Note on Uptime Monitoring:
Uptime is monitored continuously using UptimeRobot, so if the server ever βspins downβ unexpectedly, weβll know right away.
Have ideas to improve this API? Found a bug? Letβs make it better together! Open an issue or submit a pull request.
This project is licensed under the MIT License - see the LICENSE file for details.

