{"id":17520421,"url":"https://github.com/ahmedeid6842/how","last_synced_at":"2026-03-14T10:36:11.767Z","repository":{"id":198977542,"uuid":"584239601","full_name":"ahmedeid6842/How","owner":"ahmedeid6842","description":"❓🗣️ Robust Q\u0026A application built with NestJS. Empowering users with knowledge, seamless communication, and comprehensive features.","archived":false,"fork":false,"pushed_at":"2023-12-04T23:02:47.000Z","size":531,"stargazers_count":14,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"development","last_synced_at":"2025-04-23T15:49:47.997Z","etag":null,"topics":["jwt","nestjs","nodejs","nodemailer","postgres","solid-principles","typeorm","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ahmedeid6842.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}},"created_at":"2023-01-02T00:32:01.000Z","updated_at":"2025-04-02T09:50:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"1db777ed-79d0-46c3-b61b-3b3c9f2e2192","html_url":"https://github.com/ahmedeid6842/How","commit_stats":null,"previous_names":["ahmedeid6842/how"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ahmedeid6842/How","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedeid6842%2FHow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedeid6842%2FHow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedeid6842%2FHow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedeid6842%2FHow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ahmedeid6842","download_url":"https://codeload.github.com/ahmedeid6842/How/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ahmedeid6842%2FHow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279005645,"owners_count":26083940,"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","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["jwt","nestjs","nodejs","nodemailer","postgres","solid-principles","typeorm","typescript"],"created_at":"2024-10-20T11:04:51.915Z","updated_at":"2025-10-11T00:08:31.575Z","avatar_url":"https://github.com/ahmedeid6842.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\n![how-high-resolution-logo-color-on-transparent-background](https://github.com/ahmedeid6842/How/assets/57197702/ece33093-9dc2-4b87-bfb0-cca817860a72)\n\n\u003cbr\u003e\n\u003cbr\u003e\n\n---\n### 📑 Table of Contents\n- [📘 Introduction](#introduction)\n- [🚀 Live Demo](#live-demo)\n- [💻 Getting Started](#getting-started)\n  - [Prerequisites ❗](#prerequisites)\n  - [Environment Variables :key:](#environment-variables)\n  - [Setup ⬇️](#setup)\n  - [Install :heavy_check_mark: ](#install)\n  - [Usage 🤿 🏃‍♂️](#usage)\n- [🔍 APIs Reference](#api-reference)\n- [🏗️🔨 Database ERD](#erd)\n- [🔄 Sequence Diagrams](#sequence-diagram)\n- [📐 UML Diagram](#uml-diagram)\n- [👥 Author](#author)\n- [🤝 Contributing](#contribution)\n- [⭐️ Show Your Support](#support)\n- [🔭 Up Next](#up-next)\n- [💎 Lessons Learned](#lessons-learned)\n- [📜 License ](#license)\n\n## 📘 Introduction \u003ca name=\"introduction\"\u003e\u003c/a\u003e\n\u003cp align=\"center\"\u003e\nWelcome to the How Backend project! Built with NestJS, a progressive Node.js framework, How is a robust and efficient Q\u0026A application designed to empower users with knowledge and facilitate seamless communication. The How provides a SOLID foundation for building a feature-rich Q\u0026A platform, where users can share knowledge, engage in discussions, and expand their understanding. This project consists of five modules, each serving a specific purpose to deliver a comprehensive user experience.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nThe authentication module provides secure user registration, login, and password reset functionality. With guards ensuring authentication and convenient decorators like @currentUser, accessing user information is a breeze. The email module integrates Nodemailer for reliable email communication, allowing users to stay connected effortlessly. The follow module enables users to connect with others, fostering a vibrant community. The question module empowers users to create, update, and delete questions, while the answer module facilitates answering and managing questions effectively. With a focus on data management, TypeORM is utilized to define entities and establish relationships between them, simplifying database operations.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e With serialization and interception powered by the SerializeInterceptor, sensitive information is automatically excluded from outgoing responses, ensuring data privacy. \u003c/p\u003e \n\n\u003cp align=\"center\"\u003e\nTo optimize performance, caching has been implemented using Redis. The @nestjs/cache-manager package is used for caching, with Redis as the database store. The Cache-Aside Pattern and TTL (Time to Live) strategy are employed for cache management, improving response times and reducing database load.\n\u003c/p\u003e\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## 🚀 Live Demo \u003ca name=\"live-demo\"\u003e\u003c/a\u003e\n\n- [API main Live Demo Link _heroku_](https://how-fcb5f9de2993.herokuapp.com/)\n- [API alternative Demo Link _render_](https://how-backend.onrender.com/)\n\n## 💻 Getting Started \u003ca name=\"getting-started\"\u003e\u003c/a\u003e\n\nTo get a local copy up and running, follow these steps.\n\n### Prerequisites ❗\u003ca name=\"prerequisites\"\u003e\u003c/a\u003e\n\nIn order to run this project you need:\n\u003cp\u003e\n \n\u003ca href=\"https://skillicons.dev\"\u003e\n        \u003cimg src=\"https://skillicons.dev/icons?i=ts,nodejs,postgres\u0026theme=dark\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/\"\u003e\u003cimg src=\"https://authy.com/wp-content/uploads/npm-logo.png\" width=\"50px\" height=\"50\"/\u003e\u003c/a\u003e\n\n \u003c/p\u003e\n\n### Environment Variables :key: \u003ca name=\"environment-variables\"\u003e\u003c/a\u003e\nTo run this project, you will need to add the following environment variables to a new file at the root directory named `.env`:\n\n- `HOST`: the host of your project (e.g. localhost)\n- `PORT`: the port of which your project work on (e.g. 3000)\n- `DATABASE_URL`: the postgres connection string _postgres://username:password@host:port/databsename_ (e.g postgres://postgres:root@localhost:5432/How)\n- `REDIS_URL`: the redis connection string _redis://host:port_ (e.g redis://localhost:6379)\n- `JWT_SECRET`: the json web token signature to create or validate token (e.g. jwtsecret)\n- `NODEMAILER_EMAIL`: the gmail account you will use to forward email (e.g. your-email@gmail.com)\n- `NODEMAILER_PASSWORD`: you should SMTP server password form you gmail and enable you 2-step verficaiotn (watch this [video](https://www.youtube.com/watch?v=-MqVdG9w_lY) to get your password)\n- `COOKIE_SESSION_SECRET`: your cookie session secret (e.g sessionsecret)\n\n### Setup ⬇️ \u003ca name=\"setup\"\u003e\u003c/a\u003e\n1. Clone the repository:\n```shell\n   git clone https://github.com/ahmedeid6842/How\n```\n2. Change to the project directory:\n```shell\ncd ./How\n```\n\n### Install :heavy_check_mark: \u003ca name=\"install\"\u003e\u003c/a\u003e\nInstall the project dependencies using NPM:\n\n```shell\nnpm install\n```\n\n### Usage 🤿 🏃‍♂️ \u003ca name=\"usage\"\u003e\u003c/a\u003e\n\nTo start the application in development mode, run the following command:\n\n```shell\nnpm run start:dev\n```\n\nThe application will be accessible at http://localhost:3000.\n\n- Alright, it's showtime! 🔥 Hit `http://localhost:3000` and BOOM! 💥  You should see the docs page and the HOW APIs working flawlessly. ✨🧙‍♂️\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## 🔍 [APIs Reference](https://viewer.diagrams.net/?tags=%7B%7D\u0026highlight=0000ff\u0026edit=_blank\u0026layers=1\u0026nav=1#G1zp_68xm9VNrmI_5EYJxrQ3wwn3kOHgd_) \u003ca name=\"api-reference\"\u003e\u003c/a\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch3\u003e Authentication \u003c/h3\u003e \n   \u003cimg src=\"https://github.com/ahmedeid6842/How/assets/57197702/a71cf117-b429-4cb1-982e-b08318fb84ca\"/\u003e\n\n  \u003ch3\u003e Follow \u003c/h3\u003e \n   \u003cimg src=\"https://github.com/ahmedeid6842/How/assets/57197702/f964b401-1366-4760-b539-79da9c0725b2\"/\u003e\n\n  \u003ch3\u003e Question \u003c/h3\u003e \n   \u003cimg src=\"https://github.com/ahmedeid6842/How/assets/57197702/870ef0d1-ac32-43c7-8561-62fe57f9f8e2\"/\u003e\n\n  \u003ch3\u003e Answer \u003c/h3\u003e \n   \u003cimg src=\"https://github.com/ahmedeid6842/How/assets/57197702/9cf9b4d9-9ae8-4fb6-bc63-4426b84e82b3\"/\u003e\n\u003c/div\u003e\n\n## 🏗️🔨 [Database ERD](https://drawsql.app/teams/microverse-114/diagrams/how) \u003ca name=\"erd\"\u003e\u003c/a\u003e\n\n![ERD-V2](https://github.com/ahmedeid6842/How/assets/57197702/7059bb7a-1eb6-4324-9a95-33754313f946)\n\n\n## 🔄 Sequence Diagrams \u003ca name=\"sequence-diagram\"\u003e\u003c/a\u003e\n\n\u003cdiv align=\"center\"\u003e \u003ch3\u003e Auth Module \u003c/h3\u003e \u003c/div\u003e\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant AuthController\n    participant AuthService\n    participant UsersService\n    participant EmailService\n    participant JwtService\n\n    User-\u003e\u003e+AuthController: register()\n    AuthController-\u003e\u003e+AuthService: register(userCredentials)\n    AuthService-\u003e\u003e+UsersService: createUser(userCredentials)\n    UsersService--\u003e\u003e-AuthService: user\n    AuthService-\u003e\u003e+EmailService: sendRegistrationEmail(user)\n    EmailService--\u003e\u003e-AuthService: emailSent\n    AuthService--\u003e\u003e-AuthController: registrationSuccess\n\n    User-\u003e\u003e+AuthController: login(credentials)\n    AuthController-\u003e\u003e+AuthService: login(credentials)\n    AuthService-\u003e\u003e+UsersService: getUserByEmail(email)\n    UsersService--\u003e\u003e-AuthService: user\n    AuthService-\u003e\u003e+AuthService: comparePasswords(password, user.password)\n    AuthService-\u003e\u003e+JwtService: generateToken(user)\n    JwtService--\u003e\u003e-AuthService: token\n    AuthService--\u003e\u003e-AuthController: loginSuccess(token)\n\n    User-\u003e\u003e+AuthController: requestPasswordReset(email)\n    AuthController-\u003e\u003e+AuthService: requestPasswordReset(email)\n    AuthService-\u003e\u003e+UsersService: getUserByEmail(email)\n    UsersService--\u003e\u003e-AuthService: user\n    AuthService-\u003e\u003e+AuthService: generatePasswordResetToken(user)\n    AuthService-\u003e\u003e+EmailService: sendPasswordResetEmail(user, resetToken)\n    EmailService--\u003e\u003e-AuthService: emailSent\n    AuthService--\u003e\u003e-AuthController: passwordResetEmailSent()\n\n    User-\u003e\u003e+AuthController: resetPassword(resetToken, newPassword)\n    AuthController-\u003e\u003e+AuthService: resetPassword(resetToken, newPassword)\n    AuthService-\u003e\u003e+AuthService: verifyPasswordResetToken(resetToken)\n    AuthService-\u003e\u003e+UsersService: getUserById(userId)\n    UsersService--\u003e\u003e-AuthService: user\n    AuthService-\u003e\u003e+AuthService: hashPassword(newPassword)\n    AuthService-\u003e\u003e+UsersService: updatePassword(user, hashedPassword)\n    UsersService--\u003e\u003e-AuthService: updatedUser\n    AuthService--\u003e\u003e-AuthController: passwordResetSuccess()\n\n    User-\u003e\u003e+AuthController: verifyEmail(email, verificationCode)\n    AuthController-\u003e\u003e+AuthService: verifyEmail(email, verificationCode)\n    AuthService-\u003e\u003e+UsersService: getUserByEmail(email)\n    UsersService--\u003e\u003e-AuthService: user\n    AuthService-\u003e\u003e+AuthService: verifyEmail(user, verificationCode)\n    AuthService-\u003e\u003e+UsersService: updateUserVerification(user)\n    UsersService--\u003e\u003e-AuthService: updatedUser\n    AuthService--\u003e\u003e-AuthController: emailVerificationSuccess()\n\n    User-\u003e\u003e+AuthController: logout()\n    AuthController-\u003e\u003e+AuthService: logout()\n    AuthService--\u003e\u003e-AuthController: logoutSuccess()\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e \u003ch3\u003e Follow Module \u003c/h3\u003e \u003c/div\u003e\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant FollowController\n    participant FollowService\n    participant UserRepository\n    participant UserService\n\nClient-\u003eFollowController: POST /follow\nFollowController-\u003eFollowService: followUser(following_id, follower)\nFollowService-\u003eUserService: findOne(followingId)\nUserService--\u003eFollowService: following\nalt Invalid user id\n    FollowService--\u003eFollowController: Throw BadRequestException(\"Invalid user id\")\nelse\n    FollowService-\u003eFollowService: followExist(followingId, follower.id)\n    FollowService-\u003eUserService: findOne(follower.id)\n    UserService--\u003eFollowService: follower\n    alt You can't follow yourself\n        FollowService--\u003eFollowController: Throw BadRequestException(\"you can't follow yourself\")\n    else\n        alt You already a follower\n            FollowService--\u003eFollowController: Throw BadRequestException(\"you already a follower\")\n        else\n            FollowService-\u003eUserRepository: create(following, follower)\n            UserRepository--\u003eFollowService: follow\n            FollowService-\u003eUserRepository: save(follow)\n            UserRepository--\u003eFollowService: savedFollow\n            FollowService--\u003eFollowController: savedFollow\n        end\n    end\nend\n\nClient-\u003eFollowController: GET /follow/followers/:id\nFollowController-\u003eFollowService: getUserFollowers(userId)\nFollowService-\u003eUserRepository: find({ user: { id: userId } })\nUserRepository--\u003eFollowService: follows\nFollowService--\u003eFollowController: follows\n\nClient-\u003eFollowController: GET /follow/following/:id\nFollowController-\u003eFollowService: getUserFollowing(userId)\nFollowService-\u003eUserRepository: find({ follower: { id: userId } })\nUserRepository--\u003eFollowService: follows\nFollowService--\u003eFollowController: follows\n\nClient-\u003eFollowController: PATCH /follow/unfollow\nFollowController-\u003eFollowService: unFollowUser(following_id, follower)\nFollowService-\u003eUserService: findOne(followingId)\nUserService--\u003eFollowService: following\nalt Invalid user id\n    FollowService--\u003eFollowController: Throw BadRequestException(\"Invalid user id\")\nelse\n    FollowService-\u003eFollowService: followExist(followingId, follower.id)\n    alt You are not following this user\n        FollowService--\u003eFollowController: Throw BadRequestException(\"You are not following this user\")\n    else\n        FollowService-\u003eUserRepository: remove(follow)\n        UserRepository--\u003eFollowService: removedFollow\n        FollowService--\u003eFollowController: removedFollow\n    end\nend\n```\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e \u003ch3\u003e Question Module \u003c/h3\u003e \u003c/div\u003e\n\n```mermaid\nsequenceDiagram\n  participant Client\n  participant Controller\n  participant Service\n  participant Repository\n  participant QuestionLikesService\n\n  Client-\u003e\u003eController: POST /question\n  Controller-\u003e\u003eService: createQuestion()\n  alt Unique question check\n    Service-\u003e\u003eService: getQuestion({ title })\n    Service-\u003e\u003eRepository: queryBuilder.getMany()\n    Repository-\u003e\u003eService: questions\n    alt Question not unique\n      Service-\u003e\u003eController: BadRequestException\n    else\n      Service-\u003e\u003eRepository: create()\n      Repository-\u003e\u003eService: savedQuestion\n    end\n  else\n    Service-\u003e\u003eRepository: create()\n    Repository-\u003e\u003eService: savedQuestion\n  end\n\n  Service-\u003e\u003eService: addQuestion()\n\n  Client-\u003e\u003eController: GET /question\n  Controller-\u003e\u003eService: getQuestion()\n  Service-\u003e\u003eRepository: queryBuilder.getMany()\n  Repository-\u003e\u003eService: questions\n  alt No questions found\n    Service-\u003e\u003eController: NotFoundException\n  else\n    Service-\u003e\u003eController: questions\n  end\n\n  Client-\u003e\u003eController: PATCH /question/:questionId\n  Controller-\u003e\u003eService: updateQuestion()\n  Service-\u003e\u003eRepository: save()\n  Repository-\u003e\u003eService: updatedQuestion\n\n  Client-\u003e\u003eController: DELETE /question/:questionId\n  Controller-\u003e\u003eService: deleteQuestion()\n  Service-\u003e\u003eRepository: remove()\n\n  Client-\u003e\u003eController: PATCH /question/like/:questionId\n  Controller-\u003e\u003eService: likeQuestion()\n  Service-\u003e\u003eService: getQuestion()\n  Service-\u003e\u003eRepository: queryBuilder.getMany()\n  Repository-\u003e\u003eService: questions\n  alt Question not found\n    Service-\u003e\u003eController: NotFoundException\n  else\n    Service-\u003e\u003eQuestionLikesService: getLike()\n    QuestionLikesService-\u003e\u003eRepository: findOne()\n    Repository-\u003e\u003eQuestionLikesService: like\n    alt Like exists\n      Service-\u003e\u003eController: BadRequestException\n    else\n      QuestionLikesService-\u003e\u003eRepository: create()\n      Repository-\u003e\u003eQuestionLikesService: like\n      QuestionLikesService-\u003e\u003eRepository: save()\n    end\n    Service-\u003e\u003eRepository: save()\n    Repository-\u003e\u003eService: question\n  end\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e \u003ch3\u003e Answer Module \u003c/h3\u003e \u003c/div\u003e\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Controller\n    participant Service\n    participant Repository\n    participant QuestionService\n    participant AnswerLikesService\n\n    Client-\u003e\u003eController: POST /answer/:questionId\n    Controller-\u003e\u003eService: createAnswer(questionId, body, user)\n    Service-\u003e\u003eQuestionService: getQuestion({ questionId })\n    QuestionService--\u003e\u003eService: questionExist\n    alt questionExist is null\n        Service-\u003e\u003eController: throw NotFoundException\n    else questionExist is not null\n        Service-\u003e\u003eRepository: create(answer, questionExist, user)\n        Repository--\u003e\u003eService: savedAnswer\n    end\n\n    Client-\u003e\u003eController: GET /answer/?query\n    Controller-\u003e\u003eService: getAnswer(query)\n    Service-\u003e\u003eRepository: queryBuilder.getMany()\n    Repository--\u003e\u003eService: answers\n    alt answers is empty\n        Service-\u003e\u003eController: throw NotFoundException\n    else answers is not empty\n        Service--\u003e\u003eController: answers\n    end\n\n    Client-\u003e\u003eController: PATCH /answer/:answerId\n    Controller-\u003e\u003eService: updateAnswer(answer, body)\n    Service-\u003e\u003eRepository: save(answer)\n    Repository--\u003e\u003eService: updatedAnswer\n    Service--\u003e\u003eController: updatedAnswer\n\n    Client-\u003e\u003eController: DELETE /answer/:questionId/:answerId\n    Controller-\u003e\u003eService: deleteAnswer(answer)\n    Service-\u003e\u003eRepository: remove(answer)\n\n    Client-\u003e\u003eController: PATCH /answer/like/:answerId\n    Controller-\u003e\u003eService: likeAnswer(answerId, user)\n    Service-\u003e\u003eService: getAnswer({ answerId })\n    Service-\u003e\u003eAnswerLikesService: getLike(answerId, user.id)\n    AnswerLikesService--\u003e\u003eService: likeExists\n    alt likeExists is not null\n        Service-\u003e\u003eController: throw BadRequestException\n    else likeExists is null\n        Service-\u003e\u003eAnswerLikesService: addLike(answer, user)\n        Service-\u003e\u003eRepository: save(answer)\n    end\n\n```\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e \u003ch3\u003e Email Module \u003c/h3\u003e \u003c/div\u003e\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant EmailService\n    participant nodemailer\n\n    Client-\u003e\u003eEmailService: sendResetPasswordEmail(email, resetPasswordUrl)\n    EmailService-\u003e\u003enodemailer: createTransport(options)\n    nodemailer--\u003e\u003eEmailService: transporter\n    EmailService-\u003e\u003enodemailer: sendMail(message)\n    nodemailer--\u003e\u003eEmailService: result\n    EmailService--\u003e\u003eClient: result\n```\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## 📐 UML Diagram \u003ca name=\"uml-diagram\"\u003e\u003c/a\u003e\n\n```mermaid\nclassDiagram\n    class UsersService {\n        - userRepo\n        + create()\n        + findOne()\n        + find()\n        + update()\n    }\n\n    class AuthService {\n        - userService\n        - emailService\n        + register()\n        + login()\n        + sendResetPasswordEmail()\n        + resetPassword()\n    }\n\n    class FollowService {\n        - followRepo\n        - userService\n        + startUserFollowing()\n        + getUserFollowers()\n        + getUserFollowing()\n        + unFollowUser()\n    }\n\n    class QuestionService {\n        - questionRepository\n        - questionLikesService\n        + addQuestion()\n        + getQuestion()\n        + updateQuestion()\n        + deleteQuestion()\n        + likeQuestion()\n    }\n\n    class QuestionLikesService {\n        - questionLikesRepository\n        + getLike()\n        + addLike()\n    }\n\n    class EmailService {\n        - transporter\n        - email\n        - password\n        + sendResetPasswordEmail()\n    }\n\n    class AnswerService {\n        - questionService\n        - answerRepository\n        - answerLikeService\n        + createAnswer()\n        + getAnswer()\n        + updateAnswer()\n        + deleteAnswer()\n        + likeAnswer()\n    }\n\n    class AnswerLikesService {\n        - answerLikesRepository\n        + getLike()\n        + addLike()\n    }\n\n    \n\n    AuthService --\u003e EmailService : depends on\n    AuthService --\u003e UsersService : depends on\n    FollowService --\u003e UsersService : depends on\n    QuestionService --\u003e QuestionLikesService : depends on\n    AnswerService --\u003e QuestionService : depends on\n    AnswerService --\u003e AnswerLikesService : depends on\n```\n\n## 👤 Author \u003ca name=\"author\"\u003e\u003c/a\u003e\n**Ahmed Eid 🙋‍♂️**\n- Github: [@ahmedeid6842](https://github.com/ahmedeid6842/)\n- LinkedIn : [Ahmed Eid](https://www.linkedin.com/in/ahmed-eid-0018571b1/)\n- Twitter: [@ahmedeid2684](https://twitter.com/ahmedeid2684)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## 🤝 Contributing \u003ca name=\"contribution\"\u003e\u003c/a\u003e\n\nWe're always looking to improve this project! 🔍 If you notice any issues or have ideas for new features, please don't hesitate to submit a [pull request](https://github.com/ahmedeid6842/How/pulls) 🙌 or create a [new issue](https://github.com/ahmedeid6842/How/issues/new) 💡. Your contribution will help make this project even better! ❤️ 💪\n\n## ⭐️ Show your support \u003ca name=\"support\"\u003e\u003c/a\u003e\n\nIf you find this project helpful, I would greatly appreciate it if you could leave a star! 🌟 💟 \n\n## 🔭 Up next \u003ca name=\"up-next\"\u003e\u003c/a\u003e\n\n- [ ] Implement Search engine for different question searches \n- [x] Support pagination for getting questions\n- [x] Enhance the DataBase queries time by using redis LRU caching\n- [ ] Move from monolithic to microservices architecture.\n- [ ] Apply Background jobs and task scheduling Use a job queue system like Bull or Agenda to handle time-consuming tasks.\n\n\n## 💎 Lessons Learned \u003ca name=\"lessons-learned\"\u003e\u003c/a\u003e \n\n1. Secure user access with effective authentication and authorization.\n2. Use a well-structured architecture, such as Nest.js, for code organization, scalability, and maintainability.\n3. Take advantage of different NestJS components and decorators.\n4. There is something new to learn.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n## 📜 License \u003ca name=\"license\"\u003e\u003c/a\u003e\n\nThis project is licensed under the MIT License - you can click here to have more details [MIT](./LICENSE) licensed.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahmedeid6842%2Fhow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fahmedeid6842%2Fhow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fahmedeid6842%2Fhow/lists"}