Learning-Management-System-Fullstack

E-Learning Management Fullstack System

Welcome to the E-Learning Management System (LMS)! This project consists of two main components: the Frontend (built with Angular) and the Backend (developed using Django and Django REST Framework), combined with CI/CD technologies such as Docker and Jenkins. The LMS is a full-featured web application designed to manage users, courses, lessons, quizzes, and much more. This README provides a complete guide on how to set up, run, and contribute to both parts of the system.

Table of Contents

Project Overview

The E-Learning Management System is a web-based platform designed to facilitate online education and training. It provides a comprehensive set of features for managing courses, lessons, users, quizzes, and more. The system is composed of:

Because we use MongoDB, Angular, and Django, we call this a MAD-Stack application!

The MAD-Stack

The MAD-Stack is a modern web development stack that combines the following technologies:

The MAD-Stack is a powerful combination that allows developers to build scalable, responsive, and feature-rich web applications. It leverages the strengths of each technology to create a seamless user experience.

Features

Detailed Project Information:

Frontend User Interfaces

Home Page:

Home Page

Course List:

Course List

Lesson List:

Lesson List

User List:

User List

Enrollment List:

Enrollment List

Progress List:

Progress List

Login Page:

Login Page

Unauthorized Access (when not logged in):

Unauthorized Access Page

Footer:

Footer

Responsive Design: The frontend is fully responsive and optimized for all devices. Here is an example of the mobile view:

Mobile View

And many more pages & features. Feel free to explore the frontend and backend to see all the functionalities!

Available API Endpoints

Endpoint Method Description
/api/users/ GET Retrieve a list of all users.
/api/users/{id}/ GET Retrieve a specific user instance.
/api/users/ POST Create a new user instance.
/api/users/{id}/ PUT Update a specific user instance.
/api/users/{id}/ DELETE Delete a specific user instance.
/api/courses/ GET Retrieve a list of all courses.
/api/courses/{id}/ GET Retrieve a specific course instance.
/api/courses/ POST Create a new course instance.
/api/courses/{id}/ PUT Update a specific course instance.
/api/courses/{id}/ DELETE Delete a specific course instance.
/api/categories/ GET Retrieve a list of all categories.
/api/categories/{id}/ GET Retrieve a specific category instance.
/api/categories/ POST Create a new category instance.
/api/categories/{id}/ PUT Update a specific category instance.
/api/categories/{id}/ DELETE Delete a specific category instance.
/api/lessons/ GET Retrieve a list of all lessons.
/api/lessons/{id}/ GET Retrieve a specific lesson instance.
/api/lessons/ POST Create a new lesson instance.
/api/lessons/{id}/ PUT Update a specific lesson instance.
/api/lessons/{id}/ DELETE Delete a specific lesson instance.
/api/quizzes/ GET Retrieve a list of all quizzes.
/api/quizzes/{id}/ GET Retrieve a specific quiz instance.
/api/quizzes/ POST Create a new quiz instance.
/api/quizzes/{id}/ PUT Update a specific quiz instance.
/api/quizzes/{id}/ DELETE Delete a specific quiz instance.
/api/questions/ GET Retrieve a list of all questions.
/api/questions/{id}/ GET Retrieve a specific question instance.
/api/questions/ POST Create a new question instance.
/api/questions/{id}/ PUT Update a specific question instance.
/api/questions/{id}/ DELETE Delete a specific question instance.
/api/choices/ GET Retrieve a list of all choices.
/api/choices/{id}/ GET Retrieve a specific choice instance.
/api/choices/ POST Create a new choice instance.
/api/choices/{id}/ PUT Update a specific choice instance.
/api/choices/{id}/ DELETE Delete a specific choice instance.
/api/enrollments/ GET Retrieve a list of all enrollments.
/api/enrollments/{id}/ GET Retrieve a specific enrollment instance.
/api/enrollments/ POST Create a new enrollment instance.
/api/enrollments/{id}/ PUT Update a specific enrollment instance.
/api/enrollments/{id}/ DELETE Delete a specific enrollment instance.
/api/progress/ GET Retrieve a list of all progress records.
/api/progress/{id}/ GET Retrieve a specific progress record instance.
/api/progress/ POST Create a new progress record instance.
/api/progress/{id}/ PUT Update a specific progress record instance.
/api/progress/{id}/ DELETE Delete a specific progress record instance.
/api/notifications/ GET Retrieve a list of all notifications.
/api/notifications/{id}/ GET Retrieve a specific notification instance.
/api/notifications/ POST Create a new notification instance.
/api/notifications/{id}/ PUT Update a specific notification instance.
/api/notifications/{id}/ DELETE Delete a specific notification instance.

Unit Tests for APIs

The backend includes unit tests for the APIs. You can run the tests using the following command:

python manage.py test

Feel free to view and modify the tests in the core/tests.py file. Also, be sure to adjust the URLs in the test cases to match your actual URL configuration if different from the default.

File Structure

The project structure is as follows:

Learning-Management-System/
β”œβ”€β”€ LMS-Backend
β”‚   β”œβ”€β”€ .gitignore
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ manage.py
β”‚   β”œβ”€β”€ requirements.txt
β”‚   β”œβ”€β”€ LICENSE
β”‚   β”œβ”€β”€ db.sqlite3
β”‚   β”œβ”€β”€ README.md
β”‚   β”œβ”€β”€ LMSBackend/
β”‚   β”‚   β”œβ”€β”€ settings.py
β”‚   β”‚   β”œβ”€β”€ urls.py
β”‚   β”‚   β”œβ”€β”€ asgi.py
β”‚   β”‚   └── wsgi.py
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ management/
β”‚   β”‚   β”‚   └── commands/
β”‚   β”‚   β”‚       └── seed_sample_data.py
β”‚   β”‚   β”œβ”€β”€ migrations/
β”‚   β”‚   β”‚   └── __init__.py
β”‚   β”‚   β”œβ”€β”€ models.py
β”‚   β”‚   β”œβ”€β”€ views.py
β”‚   β”‚   β”œβ”€β”€ tests.py
β”‚   β”‚   β”œβ”€β”€ admin.py
β”‚   β”‚   β”œβ”€β”€ apps.py
β”‚   β”‚   β”œβ”€β”€ serializers.py
β”‚   β”‚   └── urls.py
β”œβ”€β”€ LMS-Frontend
β”‚   β”œβ”€β”€ angular.json
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ Dockerfile
β”‚   β”œβ”€β”€ README.md
β”‚   β”œβ”€β”€ LICENSE
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ login/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ login.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ login.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── login.component.css
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ footer/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ footer.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ footer.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── footer.component.css
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ header/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ header.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ header.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── header.component.css
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ pages/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ home/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ home.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ home.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── home.component.css
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ course-list/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ course-list.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ course-list.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── course-list.component.css
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ lesson-list/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ lesson-list.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ lesson-list.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── lesson-list.component.css
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ user-list/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ user-list.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ user-list.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── user-list.component.css
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ enrollment-list/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ enrollment-list.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ enrollment-list.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── enrollment-list.component.css
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ progress-list/
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ progress-list.component.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ progress-list.component.html
β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   └── progress-list.component.css
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ auth.interceptor.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ auth.service.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ user.service.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ course.service.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ lesson.service.ts
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ enrollment.service.ts
β”‚   β”‚   β”‚   β”‚   β”‚   └── progress.service.ts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ app.routes.ts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ app.component.ts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ app.config.ts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ app.config.service.ts
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ app.component.html
β”‚   β”‚   β”‚   β”‚   └── app.component.css
β”‚   β”‚   β”‚   β”œβ”€β”€ assets/
β”‚   β”‚   β”‚   β”‚   └── images/
β”‚   β”‚   β”‚   β”‚       └── .gitkeep
β”‚   β”‚   β”‚   β”œβ”€β”€ main.ts
β”‚   β”‚   β”‚   β”œβ”€β”€ styles.css
β”‚   β”‚   β”‚   β”œβ”€β”€ manifest.json
β”‚   β”‚   β”‚   └── index.html
β”‚   β”‚   β”œβ”€β”€ .editorconfig
β”‚   β”‚   β”œβ”€β”€ .gitignore
β”‚   β”‚   β”œβ”€β”€ angular.json
β”‚   β”‚   β”œβ”€β”€ package.json 
β”‚   β”‚   β”œβ”€β”€ package-lock.json
β”‚   β”‚   β”œβ”€β”€ tsconfig.json
β”‚   β”‚   β”œβ”€β”€ tsconfig.app.json
β”‚   β”‚   └── tsconfig.spec.json
β”‚   β”œβ”€β”€ LICENSE
β”‚   β”œβ”€β”€ README.md
β”œβ”€β”€ Kubernetes
β”‚   β”œβ”€β”€ configmap.yaml
β”‚   β”œβ”€β”€ backend-deployment.yaml
β”‚   β”œβ”€β”€ backend-service.yaml
β”‚   β”œβ”€β”€ frontend-deployment.yaml
β”‚   β”œβ”€β”€ frontend-service.yaml
β”œβ”€β”€ .gitignore
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Jenkinsfile
β”œβ”€β”€ LICENSE
└── README.md

Getting Started

Prerequisites

Ensure the following prerequisites are installed:

Backend Setup

Note: Before running the backend server, ensure MongoDB and Redis are running and accessible on your system. You can install MongoDB and Redis locally or use cloud services like MongoDB Atlas and Redis Cloud.

  1. Clone the repository:

    git clone https://github.com/hoangsonww/Learning-Management-System-Fullstack.git
    cd Fullstack-Learning-Management-System/LMS-Backend
    
  2. Create and activate a virtual environment:

    python -m venv .venv
    source .venv/bin/activate  # On Windows, use `.venv\Scripts\activate`
    
  3. Install dependencies:

    pip install -r requirements.txt
    
  4. Configure MongoDB and Redis:

    Ensure MongoDB and Redis are running and configured in settings.py. If not installed, follow the instructions to install them. It is very important to run MongoDB and Redis before running the backend server.

  5. Apply migrations:

    python manage.py makemigrations
    python manage.py migrate
    
  6. Create a superuser:

    python manage.py createsuperuser
    

    Follow the prompts to create a superuser account. Remember to note down the username and password because you will need it to authenticate when using the APIs later, as well as to access the Django admin panel.

  7. Put the SECRET_KEY and set Debug to True in the settings.py file:

     SECRET_KEY = 'your_secret_key_here'
     DEBUG = True
    

    Replace your_secret_key_here with a random string of characters. This key is used for cryptographic signing and should be kept secret. Or you can also contact me to get the secret key.

  8. Seed the database with sample data:

    python manage.py seed_sample_data
    
  9. Run the backend server:

    python manage.py runserver
    

    The backend server should now be running at http://127.0.0.1:8000/. If the server is run successfully, you should see the Django REST Framework browsable API interface at http://127.0.0.1:8000, as well as the following console output:

     python manage.py runserver
     Successfully seeded realistic sample data
     Successfully seeded realistic sample data
     Watching for file changes with StatReloader
     Performing system checks...
        
     System check identified no issues (0 silenced).
     September 08, 2024 - 20:35:21
     Django version 4.2.16, using settings 'LMSBackend.settings'
     Starting development server at http://127.0.0.1:8000/
     Quit the server with CONTROL-C.
    

Frontend Setup

  1. Navigate to the frontend directory:

    cd Learning-Management-System/LMS-Frontend/app
    
  2. Install dependencies:

    npm install
    
  3. Start the development server:

    ng serve
    
  4. Open the application in your browser:

    http://localhost:4200
    
  5. Test out the PWA functionality:

    • Open the application in your browser.
    • Click on the β€œInstall” button in the address bar to install the PWA.
    • Check the installed PWA in your system applications.
    • Open the installed PWA and test its functionality.

Live Frontend Demo

You can access the live frontend demo of the Learning Management System at https://learning-management-system-fullstack.vercel.app/.

Note that the backend server is not hosted, so the data will not be fetched from the server. However, you can still interact with the frontend and view the basic user interfaces (just that features like charts, notifications, and user data will not be available).

API Documentation

Authentication

Most API endpoints require authentication. Use the /api/auth/login/ endpoint to log in and obtain an authentication token.

  1. Log in to get a token:

    curl -X POST http://127.0.0.1:8000/api/auth/login/ -H "Content-Type: application/json" -d '{
      "username": "your_username",
      "password": "your_password"
    }'
    

    Use the obtained token in the Authorization header for subsequent requests:

    -H "Authorization: Token <your_token_here>"
    

Testing the APIs

You can test the API using curl, Postman, or Swagger UI.

Using curl

To test the API using curl, use the commands below. Replace <your_token_here> with the token obtained from the login endpoint.

Repeat similar curl commands for other endpoints.

Using Postman

  1. Open Postman.
  2. Create a new request for each endpoint.
  3. Set the method (GET, POST, PUT, DELETE) and URL (e.g., http://127.0.0.1:8000/api/users/).
  4. Under the β€œAuthorization” tab, choose β€œBearer Token” and paste your token.
  5. Send the request and check the response.

Using Swagger UI

  1. Navigate to the Swagger UI at http://127.0.0.1:8000/swagger/.
  2. Click on an endpoint to expand it.
  3. Click the β€œTry it out” button.
  4. Enter the required parameters and authentication token (Token <your_token_here>) in the β€œAuthorization” header. Note that the token should be prefixed with Token and a space.
  5. Click β€œExecute” to see the API response.
  6. Alternatively, you can simply click the β€œAuthorize” button in the top right corner of the page and enter your token there. This will automatically include the token in all requests. Then repeat steps 3 and 5 to test the endpoints.

Here is how the Swagger UI looks like:

Swagger UI

Using Redoc

  1. Navigate to the Redoc UI at http://127.0.0.1:8000/redoc/.
  2. Click on an endpoint to expand it.
  3. View the API documentation and test the endpoints.

Here is how the Redoc UI looks like:

Redoc UI

Using Django REST Framework Browsable API

  1. Choose any endpoint from the list above.
  2. Navigate to the endpoint URL in your browser.
  3. Log in using the superuser credentials.
  4. You will see a browsable interface where you can view the details of the endpoint.

For example, to view the list of all lessons, go to http://127.0.0.1:8000/api/lessons/. The interface should look like this:

Browsable API

Well, remember to log in first before accessing the API… Don’t forget to log in!

Seeding Sample Data

If you want to seed the database with realistic sample data, you can also run the seed_sample_data management command:

python manage.py seed_sample_data

This command will populate the database with randomly generated users, courses, categories, lessons, quizzes, questions, choices, enrollments, progress records, and notifications.

Note: By default, the seed_sample_data command will be executed when you run the python manage.py migrate command. If you don’t want to seed the database at that time, you can disable it by setting SEED_SAMPLE_DATA_ON_MIGRATE = False in the settings.py file. Also, your data might be different from mine because the data is randomly generated.

To interact with the APIs and databases more easily, you can use the following GUI tools:

For example, you can use MongoDB Compass to view the data in your MongoDB database, RedisInsight to view the data in your Redis database, and Postman to test the API endpoints, like below:

GUI Tools

Containerization

The project can be containerized using Docker. The Dockerfile and docker-compose.yml files are provided in the repository. To containerize the project, follow these steps:

  1. Change directory into the project root:

    cd Learning-Management-System
    
  2. Build the Docker image:

    docker compose up --build
    

The above command will build the Docker image and start the containers for the backend, frontend, MongoDB, and Redis. You can access the application at http://localhost:4200 and the Django REST Framework API at http://localhost:8000.

Kubernetes

The project includes Kubernetes configuration files for deploying the backend and frontend applications. The Kubernetes directory contains the following files:

To deploy the applications to a Kubernetes cluster, follow these steps:

  1. Change directory into the Kubernetes directory:

    cd Kubernetes
    
  2. Create the configmap:

     kubectl apply -f configmap.yaml
    
  3. Create the backend deployment:

    kubectl apply -f backend-deployment.yaml
    
  4. Create the backend service:

     kubectl apply -f backend-service.yaml
    
  5. Create the frontend deployment:

     kubectl apply -f frontend-deployment.yaml
    
  6. Create the frontend service:

     kubectl apply -f frontend-service.yaml
    

The above commands will create the deployments and services for the backend and frontend applications. You can access the applications using the NodePort or LoadBalancer service IP addresses.

Jenkins CI/CD

The project includes a Jenkinsfile for setting up CI/CD pipelines using Jenkins. The Jenkinsfile defines the stages for building, testing, and deploying the backend and frontend applications.

To set up the CI/CD pipelines using Jenkins, follow these steps:

  1. Install Jenkins on your system or use a cloud-based Jenkins service.

  2. Create a new Jenkins pipeline project.

  3. Configure the pipeline to use the Jenkinsfile in the project repository.

  4. Run the pipeline to build, test, and deploy the applications.

The Jenkins pipeline will automatically build the Docker images, run the unit tests, and deploy the applications to a Kubernetes cluster.

Troubleshooting

Common Issues

  1. CORS Errors:
    • Ensure backend CORS settings allow requests from http://localhost:4200.
  2. Unauthorized Access:
    • Confirm that tokens are stored correctly in localStorage.
  3. API Connection:
    • Verify the backend server is running at http://127.0.0.1:8000.
  4. Database Connection:
    • Check MongoDB and Redis are running and accessible.
  5. Dependencies:
    • Ensure all required dependencies are installed, using pip install -r requirements.txt and npm install.
  6. UI Issues:
    • Check the Angular console for errors and warnings. Alternatively, you can try clearing the cache using npm cache clean --force and npm install.

Debugging Tips

Additional Information

Refer to the README files in the LMS-Backend and LMS-Frontend directories for more detailed information on each part of the system.

These README files contain additional information on how to run, test, and contribute to the project.

Contributing

We welcome contributions! Feel free to submit issues and create pull requests.

  1. Fork the repository.
  2. Clone the forked repository to your local machine.
  3. Create a new branch and make your changes.
  4. Commit your changes and push them to your fork.
  5. Create a pull request to the main repository.
  6. I will review your changes and merge them if they are accepted.

License

This project is licensed under the MIT License.

Contact

If you have any questions or need further assistance, contact us at hoangson091104@gmail.com.

Alternatively, you can also open an issue in the repository here.


⬆ Back to Top