├── services ├── author │ ├── .gitignore │ ├── src │ │ ├── utils │ │ │ ├── db.ts │ │ │ ├── dataUri.ts │ │ │ ├── TryCatch.ts │ │ │ └── rabbitmq.ts │ │ ├── middlewares │ │ │ ├── multer.ts │ │ │ └── isAuth.ts │ │ ├── routes │ │ │ └── blog.ts │ │ ├── server.ts │ │ └── controllers │ │ │ └── blog.ts │ ├── tsconfig.json │ └── package.json ├── blog │ ├── .gitignore │ ├── src │ │ ├── utils │ │ │ ├── db.ts │ │ │ ├── TryCatch.ts │ │ │ └── consumer.ts │ │ ├── routes │ │ │ └── blog.ts │ │ ├── server.ts │ │ ├── middleware │ │ │ └── isAuth.ts │ │ └── controllers │ │ │ └── blog.ts │ ├── tsconfig.json │ └── package.json └── user │ ├── .gitignore │ ├── src │ ├── middleware │ │ ├── multer.ts │ │ └── isAuth.ts │ ├── utils │ │ ├── dataUri.ts │ │ ├── db.ts │ │ ├── GoogleConfig.ts │ │ └── TryCatch.ts │ ├── routes │ │ └── user.ts │ ├── server.ts │ ├── model │ │ └── User.ts │ └── controllers │ │ └── user.ts │ ├── tsconfig.json │ └── package.json └── frontend ├── postcss.config.mjs ├── public ├── google.png ├── vercel.svg ├── window.svg ├── file.svg ├── globe.svg └── next.svg ├── src ├── app │ ├── favicon.ico │ ├── page.tsx │ ├── blogs │ │ ├── layout.tsx │ │ └── page.tsx │ ├── layout.tsx │ ├── blog │ │ ├── saved │ │ │ └── page.tsx │ │ ├── edit │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ ├── new │ │ │ └── page.tsx │ │ └── [id] │ │ │ └── page.tsx │ ├── login │ │ └── page.tsx │ ├── profile │ │ ├── [id] │ │ │ └── page.tsx │ │ └── page.tsx │ └── globals.css ├── lib │ └── utils.ts ├── components │ ├── loading.tsx │ ├── ui │ │ ├── skeleton.tsx │ │ ├── label.tsx │ │ ├── separator.tsx │ │ ├── input.tsx │ │ ├── avatar.tsx │ │ ├── tooltip.tsx │ │ ├── card.tsx │ │ ├── button.tsx │ │ ├── dialog.tsx │ │ ├── sheet.tsx │ │ ├── select.tsx │ │ └── sidebar.tsx │ ├── BlogCard.tsx │ ├── sidebar.tsx │ └── navbar.tsx ├── hooks │ └── use-mobile.ts └── context │ └── AppContext.tsx ├── next.config.ts ├── eslint.config.mjs ├── components.json ├── .gitignore ├── tsconfig.json ├── package.json └── README.md /services/author/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .env 4 | Dockerfile 5 | .dockerignore -------------------------------------------------------------------------------- /services/blog/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .env 4 | Dockerfile 5 | .dockerignore -------------------------------------------------------------------------------- /services/user/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .env 4 | Dockerfile 5 | .dockerignore -------------------------------------------------------------------------------- /frontend/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: ["@tailwindcss/postcss"], 3 | }; 4 | 5 | export default config; 6 | -------------------------------------------------------------------------------- /frontend/public/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meprashantkumar/blog-microservice-project-2025/HEAD/frontend/public/google.png -------------------------------------------------------------------------------- /frontend/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meprashantkumar/blog-microservice-project-2025/HEAD/frontend/src/app/favicon.ico -------------------------------------------------------------------------------- /frontend/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { redirect } from "next/navigation"; 2 | import React from "react"; 3 | 4 | const Home = () => { 5 | return redirect("/blogs"); 6 | }; 7 | 8 | export default Home; 9 | -------------------------------------------------------------------------------- /services/author/src/utils/db.ts: -------------------------------------------------------------------------------- 1 | import { neon } from "@neondatabase/serverless"; 2 | import dotenv from "dotenv"; 3 | 4 | dotenv.config(); 5 | 6 | export const sql = neon(process.env.DB_URL as string); 7 | -------------------------------------------------------------------------------- /services/blog/src/utils/db.ts: -------------------------------------------------------------------------------- 1 | import { neon } from "@neondatabase/serverless"; 2 | import dotenv from "dotenv"; 3 | 4 | dotenv.config(); 5 | 6 | export const sql = neon(process.env.DB_URL as string); 7 | -------------------------------------------------------------------------------- /frontend/src/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /services/author/src/middlewares/multer.ts: -------------------------------------------------------------------------------- 1 | import multer from "multer"; 2 | 3 | const storage = multer.memoryStorage(); 4 | 5 | const uploadFile = multer({ storage }).single("file"); 6 | 7 | export default uploadFile; 8 | -------------------------------------------------------------------------------- /services/user/src/middleware/multer.ts: -------------------------------------------------------------------------------- 1 | import multer from "multer"; 2 | 3 | const storage = multer.memoryStorage(); 4 | 5 | const uploadFile = multer({ storage }).single("file"); 6 | 7 | export default uploadFile; 8 | -------------------------------------------------------------------------------- /frontend/next.config.ts: -------------------------------------------------------------------------------- 1 | import type { NextConfig } from "next"; 2 | 3 | const nextConfig: NextConfig = { 4 | /* config options here */ 5 | eslint: { 6 | ignoreDuringBuilds: true, 7 | }, 8 | }; 9 | 10 | export default nextConfig; 11 | -------------------------------------------------------------------------------- /frontend/src/components/loading.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Loading = () => { 4 | return ( 5 |
Loading...
7 |No saved blogs yet!
37 | )} 38 |
32 |
{desc.slice(0, 30)}...
39 |No Blogs Yet
} 35 | {blogs && 36 | blogs.map((e, i) => { 37 | return ( 38 |{user?.name}
58 |{user.bio}
64 |{user?.name}
138 |{user.bio}
144 |
199 |
203 |
208 | {author?.name}
209 |
210 | {isAuth && (
211 |
220 | )}
221 | {blog.author === user?._id && (
222 | <>
223 |
229 |
238 | >
239 | )}
240 |
{blog.description}
249 | 253 |
288 |
289 |
{e.comment}
294 |295 | {new Date(e.create_at).toLocaleString()} 296 |
297 |No Comments Yet
312 | )} 313 |