{"id":21091149,"url":"https://github.com/manikmaity/imagegram","last_synced_at":"2026-04-12T06:32:20.883Z","repository":{"id":260085109,"uuid":"880225161","full_name":"ManikMaity/ImageGram","owner":"ManikMaity","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-05T07:00:55.000Z","size":1919,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-01T13:06:57.542Z","etag":null,"topics":["authentication","authorization","backend","bcrypt","cloudinary","documentation","expressjs","jwt","mongodb","mongoose","swagger","swagger-ui","zod"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ManikMaity.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2024-10-29T10:53:01.000Z","updated_at":"2024-11-05T07:00:58.000Z","dependencies_parsed_at":"2025-07-01T13:17:20.338Z","dependency_job_id":null,"html_url":"https://github.com/ManikMaity/ImageGram","commit_stats":null,"previous_names":["manikmaity/imagegram"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ManikMaity/ImageGram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManikMaity%2FImageGram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManikMaity%2FImageGram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManikMaity%2FImageGram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManikMaity%2FImageGram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ManikMaity","download_url":"https://codeload.github.com/ManikMaity/ImageGram/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ManikMaity%2FImageGram/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265793684,"owners_count":23829180,"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":["authentication","authorization","backend","bcrypt","cloudinary","documentation","expressjs","jwt","mongodb","mongoose","swagger","swagger-ui","zod"],"created_at":"2024-11-19T21:43:47.019Z","updated_at":"2026-04-12T06:32:15.804Z","avatar_url":"https://github.com/ManikMaity.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MVC Arcitecture\n- Hepls to structured the backend application well\n- MVC Architecture is a pattern to write server-side applications that divides the application into three parts: Model, View, and Controller\n\n- View is the layer that users interact with the application, and Controller is the layer that receives user req and send it to Model. and receive the response from Model and return it to the View.\n\n```\nView (req) --\u003e Controller --\u003e Model\nModel (res) --\u003e Controller --\u003e View\n```\n\n## MVC Architecture\n### Frontend Project\n- View (React / Frontend Project)\n\n### Backend Project\n- Controller\n- Model\n\n## More broader approaches\n\n```\nView --\u003e Routing Layer --\u003e Validation Layer --\u003e Controller Layer (Receives user req and send it to Service) --\u003e Service Layer (Contain functions and classes to handle business logic) --\u003e Repository Layer --\u003e Schema Layer\n```\n### Other Layer\n```\nAPI Layer, Configuration Layer, util/helper Layer, DTO Layer\n```\n\n### Repository design pattern\n- Segregate DB intractions from business logic to a new Layer.\n- This Layer is called Repository  Layer / DAO Layer (Data Access Layer).\n- Inside the Repository Layer, we can use any ORM or RAW queries.\n\n### Schema Layer\n- In the schema layer, we define the schema of the database.\n\n### Validation on code level\n- In mongose we can define the validation on code with the Schema.\n```js\nimport mongoose, { Schema } from \"mongoose\";\n\nconst userSchema = new Schema({\n    email : {\n        type : String,\n        required : true,\n        unique : true,\n        \n\n    },\n    password : {\n        type : String,\n        required : true\n    }\n});\n\nconst UserModel = mongoose.model(\"User\", userSchema);\nexport default UserModel;\n```\n\n- We can include our custom validation using regex.\n```js\nemail : {\n        type : String,\n        required : true,\n        unique : true,\n        validate : {\n            validator : (value) =\u003e {\n                return /^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$/.test(value);\n            },\n            message : (props) =\u003e `${props.value} is not a valid email`\n        }\n\n    },\n```\n- In mongoose Schma we can pass {timestaps : true} with the Schema Obj which will provide create and update date automacic\n\n\n## Task\n- Make a Post Schema \n```js\nimport mongoose, { Schema } from \"mongoose\";\n\nconst postSchema = new Schema({\n    postContent : {\n        type : String,\n        reqiured : true,  \n    },\n    user : {\n        type : Schema.ObjectId,\n        reqiured : true\n    },\n    image : {\n        type : String,\n        reqiured : true,\n        validate : {\n            validator : (value) =\u003e {\n                return /^(https?:\\/\\/.*\\.(?:png|jpg|jpeg|gif|bmp|webp|svg))$/i.test(value)\n            },\n            message : \"Invalid Image url\"\n        }\n    }\n\n}, {timestamps : true})\n```\n## FIX\n- We make also directly take image and convert it to `base64` string and store the image in the db.\n- But this will take lots storage and database become messy because the image strig is long.\n- Thats why we can use `amazon s3` bucket to store the image.\n- s3 will take image and return the url of the image.\n\n```js\n    user : {\n        type : Schema.ObjectId,\n        ref : \"User\",\n        reqiured : true\n    },\n```\n- In mongoose when we have to do relationship we need to use `ref` in the schema.\n\n\n## HOMEWORK - \n- Upload the image in cloudinary and store thr url in the database.\n- Done\n```js\nimport { v2 as cloudinary } from \"cloudinary\";\nimport { CLOUDINARY_KEY, CLOUDINARY_SECRECT } from \"./serverConfig.js\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { dirname } from \"path\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\ncloudinary.config({\n  cloud_name: \"dp4roeps2\",\n  api_key: CLOUDINARY_KEY,\n  api_secret: CLOUDINARY_SECRECT,\n});\n\nexport async function uploadImageInCloudinary(imagename) {\n  try {\n    const relativePath = path.join(__dirname, `../../public/${imagename}`);\n    const result = await cloudinary.uploader.upload(relativePath);\n    console.log(\"Image uploaded successfully\");\n    console.log(result);\n    console.log(result.url);\n    return result?.url;\n  } catch (err) {\n    console.log(err);\n    throw new Error(err);\n  }\n}\n```\n\n## Routes\n- We can use `express` router to handle the routes.\n- When we use something like `https://example.com/api/user` that mean its a api route\n- There is other type of route like `http://example.com/user` that mean its a web route\n\n### API Versioning\n- Using this we can make multiple version of the api.\n- Like `https://example.com/api/v1/user` and `https://example.com/api/v2/user`\n- We can define single route inside our index.js like `/api` and in the api route we can define the other routes like `/user, /post, `etc. We can use `apiRouter.use()` to do that.\n```js\nimport express from \"express\";\nimport userRouter from \"./user.js\";\nimport postRouter from \"./post.js\";\nconst apiRouter = express.Router();\n\napiRouter.use(\"/user\", userRouter);\napiRouter.use(\"/post\", postRouter);\n\n\nexport default apiRouter;\n```\n### TASK make a V1 router and make a V2 router \n\n```js\nimport express from \"express\";\nimport userRouter from \"../user.js\";\nimport postRouter from \"../post.js\";\nconst v1Router = express.Router();\n\nv1Router.use(\"/user\", userRouter);\nv1Router.use(\"/post\", postRouter);\n\n\nexport default v1Router;\n```\n\n```js\nimport express from \"express\";\nimport userRouter from \"./user.js\";\nimport postRouter from \"./post.js\";\nimport v1Router from \"./v1/v1Router.js\";\nconst apiRouter = express.Router();\n\napiRouter.use(\"/v1\", v1Router);\n\nexport default apiRouter;\n```\n\n- Done, now we can use `http://localhost:3000/api/v1/post/all` to access the all post.\n- FIXDone: All the other routes like `user` and `post` should be inside the v1 folder.\n\n## TASK - \n- Done - Implement the `delete` and `update` route\n\n## HW -\n- Implement a logic to delete the exiting image from cloudinary when image is updated or post deleted.\n\n## Triggers \n- Every database have triggers.\n- Triggers are used to do just before and after some action happens in the database.\n- In mongoose triggers are called hook and there is `pre` and `post` hooks.\n- `pre` hooks are called before the action and `post` hooks are called after the action.\n- These are used in the `Schema` or `Model` Layer.\n```js\nuserSchema.pre(\"save\", function modifyPassword(next){\n    const user = this;\n    const hashedPassword = bcrypt.hashSync(user.password, SALT_ROUND);\n    user.password = hashedPassword;\n    next();\n})\n```\n## Authentication\n- Authentication is the process of verifying that a user is who they say they are.\n- Most common way of authentication is with JWT.\n\n### [JWT](www.jwt.io)\n- JSON Web Token\n- JWT have 3 parts - header, payload, signature\n- Payload is the data that we want to store in the token like {_id : \"mani123}.\n- header provide information about the type of token\n- signature is used to verify and make the token. Secret key.\n**Note** - The signin details like email, password should come fro rew body because if send \nthem confidential using peram or query string it will be stored in history of the user.\n\n### Steps In Signin\n- Fist get will get the email and password from the body\n- then we have to find the user in the database using email\n- them uisng bycrypt compare the database password with the user given password\n- Then make a JWT token uisng user._id and send it to the user\n\n### TASK -\nMake a signin functionality using JWT\n- Done ✔️\n\n## Tommorow Class Authorization - \n- HW - Exprore Authorization\n\n## Authorization\n- TASK  - Get the user id from auth and provide it in post object - Done ✔️\n- Get user name and email details from ref data in post object in mongodb without doing an extra database call - Done ✔️\n\n### Populate\n- We can use the `.populate()` method on the `user` field in your Mongoose query. This will retrieve the referenced User document directly within the same query, allowing you to access the user's name and other details without an extra call.\n\n```javascript\nexport const getPaginatedPosts = async (offset, limit) =\u003e {\n    try {\n        const posts = await PostModel.find()\n            .sort({ \"createdAt\": -1 })\n            .skip(offset)\n            .limit(limit)\n            .populate(\"user\", \"username email _id\"); // Populating only the 'name' field of the 'user'\n\n        return posts;\n    } catch (err) {\n        console.error(err);\n        throw new Error(err);\n    }\n};\n```\n\nIn the `.populate(\"user\", \"name\")` part:\n- The first argument (`\"user\"`) specifies the field you want to populate.\n- The second argument (`\"name\"`) specifies the fields you want to retrieve from the `User` document. You can list additional fields (e.g., `\"name email\"`) if needed.\n\n---\n**TASK -** :The owner of the post can delete his post.\n- Done ✔️\n\n## Authorisation\n- Authorisation is the process of deciding what a user is allowed to do.\n- Authorisation process is done after authentication.\n- `role`property is used in the `userSchema` to define the role of the user.\n```js\n    role : {\n        type : String,\n        enum : [\"user\", \"admin\"],\n        default : \"user\"\n    }\n```\n- **TASK** - Attatch auth and authorisation to update post route so that only admin can edit it.\n- Done ✔️\n\n## Documentation\n- We can use `swagger-jsdoc` to generate good and understandable documentation for our API.\n- [swagger-jsdoc](https://swagger.io/docs/)\n- `swagger-jsdoc` is a library that generates swagger documentation for our API.\n\n### Process\n- Import `swagger-jsdoc` and `swagger-ui-express` npm packages.\n- import `swaggerJsdoc` and `swaggerUi` from `swagger-jsdoc` and `swagger-ui-express` respectively in `index.js`.\n- `swaggerJsdoc` takes `options` as an argument.\n- Have to make a `swaggerOption.js` file in `utils` folder.\n```js\nexport const options = {\n    definition: {\n      openapi: '3.0.0',\n      info: {\n        title: 'ImageGram API',\n        version: '1.0.0',\n        description: 'API for ImageGram',\n      },\n      servers: [\n        {\n          url: 'http://localhost:3000/api/v1',\n        },\n      ],\n    },\n    apis: ['./src/Routes/v1/*.js'], // files containing annotations as above\n  };\n```\n- `swaggerJsdoc` takes `options` as an argument and returns `swaggerDocument`.\n- Then we have to use `swaggerUi.serve` and `swaggerUi.setup` to serve the swagger documentation.\n```js\n// index.js\nimport swaggerJsdoc from \"swagger-jsdoc\";\nimport swaggerUi from \"swagger-ui-express\";\nimport {options} from \"./utils/swaggerOption.js\"\n\nconst swaggerDocument = swaggerJsdoc(options);\n\nconst app = express();\nconst PORT = 3000;\napp.use(express.json());\n\nawait connectDB();\napp.use(\"/api\", apiRouter);\napp.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));\n\napp.listen(PORT, () =\u003e {\n    console.log(\"Server started on port http://localhost:3000\");\n});\n```\n- Now we can write the documentation for api route using comments.\n```js\n/**\n * @swagger\n * /signup:\n *  post:\n *     summary: Create user\n *     description: Create a new user\n *     requestBody:\n *      required: true\n *      content:\n *          application/json:\n *             \n *     responses:\n *          200:\n *              description: User created successfully\n *          500:\n *              description: Internal server error\n *          400:\n */\nv1Router.post(\"/signup\", validate(zodSignupValidation), signupController)\n```\n\n**HW** - Implement the `like` and `comment` route\n- There is diff type of likes in instagram like \"heart\" and \"thumbs up\".\n- Likes can be done on post and comment.\n- Comment can be done on post and comment. - Done ✔️\n\n## Deployment\n- We can deploy our backend application using `AWS` (paid) or `Render` (free).\n### Render\n- Go to render.com\n- Click on `new` and select `web service`\n- Chose the project to deploy or give the github public link\n- Chose the deside directory\n- Give the build and start command, ex- `npm install \u0026\u0026 npm run start`\n- Choose the free plan\n- Fill up .env details\n\n## Custom Loadbalancer\n- Loadbalancer is a server that distributes traffic to multiple servers.\n```\nclient ----\u003e loadbalancer ----\u003e server1\n\n                     or   -----\u003e server2\n```\n- first install the `ip` npm package, this will help us to get the public ip of the server client.\n```bash\nnpm i ip\n```\n- now we can get the ip address of the client using `ip` package.\n```js\nconst ip = require(\"ip\");\nconst publicIp = ip.address();\nconsole.log(publicIp);\n```\n\n## Rate Limiting \n- Rate limiting is the process of limiting the number of requests that can be made to a server in a given time period.\n- It prevents ddos attacks.\n- npm package - [express-rate-limit](https://www.npmjs.com/package/express-rate-limit)\n- Have to make a limiter object.\n```js\nconst limiter = rateLimit({\n    windowMs: 0.5 * 60 * 1000, \n\tlimit: 5, \n    \n})\n```\n```js\napp.use(limiter);\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanikmaity%2Fimagegram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanikmaity%2Fimagegram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanikmaity%2Fimagegram/lists"}