{"id":19243815,"url":"https://github.com/amrdb/private-lessons-lms","last_synced_at":"2025-04-21T09:33:23.138Z","repository":{"id":50282662,"uuid":"440680541","full_name":"amrdb/private-lessons-lms","owner":"amrdb","description":"During Covid-19 teachers started to give private lessons online, so this is a LMS for a private instructor that supports assistants and multiple grades for a specific subject/course","archived":false,"fork":false,"pushed_at":"2024-04-26T10:47:22.000Z","size":505,"stargazers_count":42,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-01T12:11:10.645Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amrdb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"License","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-21T23:49:13.000Z","updated_at":"2025-03-30T06:15:38.000Z","dependencies_parsed_at":"2024-10-30T06:02:09.009Z","dependency_job_id":null,"html_url":"https://github.com/amrdb/private-lessons-lms","commit_stats":null,"previous_names":["amrdb/private-lessons-lms"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amrdb%2Fprivate-lessons-lms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amrdb%2Fprivate-lessons-lms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amrdb%2Fprivate-lessons-lms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amrdb%2Fprivate-lessons-lms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amrdb","download_url":"https://codeload.github.com/amrdb/private-lessons-lms/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250032413,"owners_count":21363833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T17:20:13.696Z","updated_at":"2025-04-21T09:33:18.103Z","avatar_url":"https://github.com/amrdb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Private Lessons/Courses LMS API\n\n## Techs:\n\n- Node.js/ExpressJS\n- Socket.IO\n- PassportJS\n- MongoDB/Mongoose\n- Redis\n- Google Cloud Storage (Firebase Admin SDK)\n- Firebase Cloud Messaging (FCM)\n- SendGrid\n- Sentry\n- Postman\n- Docker\n- Documented with JsDoc\n\n## System Architecture:\n\n[![System Architecture](https://github.com/Amr2812/private-lessons-lms/blob/master/.github/Architecture.png)](https://github.com/Amr2812/private-lessons-lms/blob/master/.github/Architecture.png)\n\n## Server Structure:\n\n[![Server Structure](https://github.com/Amr2812/private-lessons-lms/blob/master/.github/Structure.png)](https://github.com/Amr2812/private-lessons-lms/blob/master/.github/Structure.png)\n\n## Features:\n\nAn overview of the LMS API.\n\n\u003e **Note:** This is not all the API endpints but the most important features. A postman documentaion is available at the end of this document.\n\n- **Authentication \u0026 Authorization:**\n\n  - Sessions handling with express-session using Redis as a session store\n  - Facebook authentication OAuth2.0\n  - PassportJS for authentication\n  - Signup\n  - Login\n  - Logout\n  - Forgot Password\n  - Password Reset\n\n- **User Management:**\n\n  - Roles\n    - _Role 1:_ Student\n    - _Role 2:_ Assistant\n    - _Role 3:_ Instructor\n  - User Profile\n  - User Profile Update\n  - Filter/Search Users\n  - Handle FCM Tokens and topics\n\n- **Grades:**\n\n  - Create Grade\n  - Get Grades\n\n- **Lessons:**\n\n  - Create Lesson\n  - Update Lesson\n  - Publish/Unpublish Lesson and send notifications \u0026 emails to students\n  - Attend Lesson\n  - Filter/Search Lessons\n  - Attend Lessons By access codes\n  - Stream videos with the Node.js server to prevent file link access\n\n- **Quizes (Exams unrelated to lessons):**\n\n  - Create Quiz\n  - Update Questions\n  - Publish/Unpublish Quiz and send notifications \u0026 emails to students\n  - Filter/Search Quizes\n  - Take Quizzes By access codes\n\n- **Access codes:**\n\n  - Create Access Codes for grades\n  - Access Codes Types (Lessons - Quizzes)\n  - Track admin actions (generate access codes) by role 3 (Instructor)\n\n- **Realtime chat with admins**\n\n  - Ask/Chat with admins about lessons if attended\n  - Redis Pub/Sub as a Socket.IO Adapter for horizontal scaling (multiple servers communication)\n  - Dependency Injection for Socket.IO structure\n\n- **Notification/Email Service**\n\n  - SendGrid as an Email service\n  - Firebase Cloud Messaging (FCM) as a Notification service\n  - Node.js EventEmitter Pub/Sub as a Notification service emitter\n\n## About the APP:\n\n- **Scaling:**\n\n  The app is scalable horizontally and can be deployed to multiple servers and/or multiple instances as it is stateless and WebSockets servers communicate through redis to preserve state.\n\n- **Design Patterns:**\n\n  I used the Strategy deisgn pattern to implement multiple authentication strategies (Session-based and OAuth2.0 Facebook authentication).\n  I used the Observer design pattern (with Node.js EventEmitter) to asynchronously subscribe to events like published lessons and notify students.\n\n- **Database Performance:**\n\n  Due to the fact that the app load will be mainly from reads so I could use indexes freely so I used sutible indexes like compound indexes \u0026 text indexes for the database queries/sorts and I could track query optimizer usage by MongoDB Compass Explain plain and Apply what I've learned in the MongoDB Performance course from MongoDB University.\n\n- **File Upload:**\n\n  - Multer as a streaming middleware between client and Google Cloud Storage as I built a custom storage class and factory for it for uploading profile pictures\n  - Google Cloud Storage Signed URLs for uploading lessons/videos\n\n- **Logging:**\n\n  - Logging with WinstonJS\n  - Error Reporting with Sentry\n  - Logging Requests with Morgan\n\n- **Error Handling:**\n\n  - Error Handling with @Hapi/Boom for error responses\n  - Custom middleware for sending error responses\n  - Asyncronous error catching with a wrapped function for all controllers\n  - Report unexpected errors to sentry\n\n- **Security:**\n\n  - Rate Limiting with Token Bucket Algorithm (Redis as Token Store)\n  - XSS Protection (HelmetJS)\n  - CORS Protection\n\n- **Code Style:**\n\n  - Code Style with Prettier\n  - Hsuky \u0026 lint-staged as a pre-commit hook to automatically format code using prettier\n\n## Postman Documentaion\n\n- Postman collection for the API endpoints:\n  - [View](https://github.com/Amr2812/private-lessons-lms/blob/master/.github/LMS_API.postman_collection)\n- Postman collection for the Socket.IO events:\n  - Unavilable as WebSockets at postman was still in beta version and couldn't be exported\n\n## Commercial use\n\nI restrict any individual or company to use this project commercially.\nIts source is available for reviewing by potential recruiters or clients and developers/students who find the project useful to learn from.\n\n\u003e Give it a star if you like it ⭐\n\n## Contact me\n\n\u003cp align=\"center\"\u003e\n\u003cul\u003e\n  \u003cli\u003e\n    \u003ca href=\"https://www.linkedin.com/in/amr-elmohamady\" target=\"_blank\" \u003eLinkedIn\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"mailto:amr.osama.elmohamady@gmail.com\"\u003eEmail\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"https://amrelmohamady.hashnode.dev/\" target=\"_blank\" \u003eBlog \u0026 Personal site (hashnode)\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"https://dev.to/amrelmohamady\" target=\"_blank\" \u003eBlog (dev.to)\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"https://www.facebook.com/amr.elmohamady.1426/\" target=\"_blank\" \u003eFacebook\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"https://twitter.com/Amr__Elmohamady\" target=\"_blank\" \u003eTwitter\u003c/a\u003e \n  \u003c/li\u003e\n\u003c/ul\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famrdb%2Fprivate-lessons-lms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famrdb%2Fprivate-lessons-lms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famrdb%2Fprivate-lessons-lms/lists"}