From 47d30d96ebca33d0dec63f37f4e4caa64ecfd22b Mon Sep 17 00:00:00 2001 From: Md Sharafat Hassain Binoy Date: Mon, 27 Apr 2026 00:03:06 +0600 Subject: [PATCH 01/11] Template API: create database schema --- .../migration.sql | 207 ++++++++++++++++++ prisma/schema/template.prisma | 139 ++++++++++++ .../modules/template/template.controller.ts | 66 ++++++ src/app/modules/template/template.route.ts | 22 ++ src/app/modules/template/template.service.ts | 46 ++++ src/app/modules/template/template.swagger.ts | 106 +++++++++ .../modules/template/template.validation.ts | 9 + src/routes.ts | 2 + src/swaggerOptions.ts | 2 + 9 files changed, 599 insertions(+) create mode 100644 prisma/migrations/20260426174845_add_template_data_tables/migration.sql create mode 100644 prisma/schema/template.prisma create mode 100644 src/app/modules/template/template.controller.ts create mode 100644 src/app/modules/template/template.route.ts create mode 100644 src/app/modules/template/template.service.ts create mode 100644 src/app/modules/template/template.swagger.ts create mode 100644 src/app/modules/template/template.validation.ts diff --git a/prisma/migrations/20260426174845_add_template_data_tables/migration.sql b/prisma/migrations/20260426174845_add_template_data_tables/migration.sql new file mode 100644 index 0000000..c768a98 --- /dev/null +++ b/prisma/migrations/20260426174845_add_template_data_tables/migration.sql @@ -0,0 +1,207 @@ +-- CreateTable +CREATE TABLE "Template" ( + "id" TEXT NOT NULL, + "language" TEXT NOT NULL, + "deliveryCharge" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Template_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Banner" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "bannerTitle" TEXT NOT NULL, + "bannerDesc" TEXT NOT NULL, + "bannerImage" TEXT NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Banner_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Address" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "phoneNumber" TEXT NOT NULL, + "shopLocation" TEXT NOT NULL, + "shopEmail" TEXT NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Address_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Ingredient" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Ingredient_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ingredientOptions" ( + "id" TEXT NOT NULL, + "ingrImg" TEXT NOT NULL, + "ingrTitle" TEXT NOT NULL, + "ingrDes" TEXT NOT NULL, + "ingredientId" TEXT NOT NULL, + + CONSTRAINT "ingredientOptions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Instruction" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "instBanner" TEXT NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Instruction_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "InstructionOptions" ( + "id" TEXT NOT NULL, + "hint" TEXT NOT NULL, + "detail" TEXT NOT NULL, + "instructionId" TEXT NOT NULL, + + CONSTRAINT "InstructionOptions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FAQ" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "FAQ_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "FAQOptions" ( + "id" TEXT NOT NULL, + "index" INTEGER NOT NULL, + "text" TEXT NOT NULL, + "faqId" TEXT NOT NULL, + + CONSTRAINT "FAQOptions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Tips" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "tipsBanner" TEXT NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Tips_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TipsOption" ( + "id" TEXT NOT NULL, + "index" INTEGER NOT NULL, + "text" TEXT NOT NULL, + "tipsId" TEXT NOT NULL, + + CONSTRAINT "TipsOption_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PriceCombo" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "PriceCombo_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PriceOption" ( + "id" TEXT NOT NULL, + "quantity" TEXT NOT NULL, + "price" TEXT NOT NULL, + "comboId" TEXT NOT NULL, + + CONSTRAINT "PriceOption_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Product" ( + "id" TEXT NOT NULL, + "isVisible" BOOLEAN NOT NULL, + "price" TEXT NOT NULL, + "discount" INTEGER NOT NULL, + "productName" TEXT NOT NULL, + "templateId" TEXT NOT NULL, + + CONSTRAINT "Product_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Banner_templateId_key" ON "Banner"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Address_templateId_key" ON "Address"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Ingredient_templateId_key" ON "Ingredient"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Instruction_templateId_key" ON "Instruction"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "FAQ_templateId_key" ON "FAQ"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Tips_templateId_key" ON "Tips"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PriceCombo_templateId_key" ON "PriceCombo"("templateId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Product_templateId_key" ON "Product"("templateId"); + +-- AddForeignKey +ALTER TABLE "Banner" ADD CONSTRAINT "Banner_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Address" ADD CONSTRAINT "Address_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Ingredient" ADD CONSTRAINT "Ingredient_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ingredientOptions" ADD CONSTRAINT "ingredientOptions_ingredientId_fkey" FOREIGN KEY ("ingredientId") REFERENCES "Ingredient"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Instruction" ADD CONSTRAINT "Instruction_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "InstructionOptions" ADD CONSTRAINT "InstructionOptions_instructionId_fkey" FOREIGN KEY ("instructionId") REFERENCES "Instruction"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FAQ" ADD CONSTRAINT "FAQ_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "FAQOptions" ADD CONSTRAINT "FAQOptions_faqId_fkey" FOREIGN KEY ("faqId") REFERENCES "FAQ"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Tips" ADD CONSTRAINT "Tips_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TipsOption" ADD CONSTRAINT "TipsOption_tipsId_fkey" FOREIGN KEY ("tipsId") REFERENCES "Tips"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PriceCombo" ADD CONSTRAINT "PriceCombo_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "PriceOption" ADD CONSTRAINT "PriceOption_comboId_fkey" FOREIGN KEY ("comboId") REFERENCES "PriceCombo"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Product" ADD CONSTRAINT "Product_templateId_fkey" FOREIGN KEY ("templateId") REFERENCES "Template"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema/template.prisma b/prisma/schema/template.prisma new file mode 100644 index 0000000..027c5e7 --- /dev/null +++ b/prisma/schema/template.prisma @@ -0,0 +1,139 @@ +model Template { + id String @id @default(uuid()) + language String + deliveryCharge String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + address Address? + banner Banner? + ingredient Ingredient? + instruction Instruction? + faq FAQ? + tips Tips? + priceCombo PriceCombo? + product Product? +} + +// banner model +model Banner { + id String @id @default(uuid()) + isVisible Boolean + bannerTitle String + bannerDesc String + bannerImage String + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) +} + +// address model +model Address { + id String @id @default(uuid()) + isVisible Boolean + phoneNumber String + shopLocation String + shopEmail String + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) +} + +//ingredient model +model Ingredient { + id String @id @default(uuid()) + isVisible Boolean + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) + options ingredientOptions[] +} + +//ingredient options model +model ingredientOptions { + id String @id @default(uuid()) + ingrImg String + ingrTitle String + ingrDes String + ingredientId String + ingredient Ingredient @relation(fields: [ingredientId], references: [id]) +} + +//instruction model & instruction options +model Instruction { + id String @id @default(uuid()) + isVisible Boolean + instBanner String + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) + options InstructionOptions[] +} + +model InstructionOptions { + id String @id @default(uuid()) + hint String + detail String + instructionId String + instruction Instruction @relation(fields: [instructionId], references: [id]) +} + +//FAQ & FAQOptions model +model FAQ { + id String @id @default(uuid()) + isVisible Boolean + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) + options FAQOptions[] +} + +model FAQOptions { + id String @id @default(uuid()) + index Int + text String + + faqId String + faq FAQ @relation(fields: [faqId], references: [id]) +} + +//Tips & Tips options model +model Tips { + id String @id @default(uuid()) + isVisible Boolean + tipsBanner String + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) + options TipsOption[] +} + +model TipsOption { + id String @id @default(uuid()) + index Int + text String + + tipsId String + tips Tips @relation(fields: [tipsId], references: [id]) +} + +//PriceCombo & PriceComboOptions model +model PriceCombo { + id String @id @default(uuid()) + isVisible Boolean + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) + options PriceOption[] +} + +model PriceOption { + id String @id @default(uuid()) + quantity String + price String + comboId String + combo PriceCombo @relation(fields: [comboId], references: [id]) +} + +//product model +model Product { + id String @id @default(uuid()) + isVisible Boolean + price String + discount Int + productName String + templateId String @unique + template Template @relation(fields: [templateId], references: [id]) +} diff --git a/src/app/modules/template/template.controller.ts b/src/app/modules/template/template.controller.ts new file mode 100644 index 0000000..b89d917 --- /dev/null +++ b/src/app/modules/template/template.controller.ts @@ -0,0 +1,66 @@ +import catchAsync from "../../utils/catch_async.js"; +import manageResponse from "../../utils/manage_response.js"; +import { template_service } from "./template.service.js"; + +const get_all_template = catchAsync(async (req, res) => { + const result = await template_service.get_all_template_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "All template fetched successfully.", + data: result, + meta: {}, + }); +}); + +const get_single_template = catchAsync(async (req, res) => { + const result = await template_service.get_single_template_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "Single template fetched successfully.", + data: result, + meta: {}, + }); +}); + +const create_template = catchAsync(async (req, res) => { + const result = await template_service.create_template_into_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "template created successfully.", + data: result, + meta: {}, + }); +}); + +const update_template = catchAsync(async (req, res) => { + const result = await template_service.update_template_into_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "template updated successfully.", + data: result, + meta: {}, + }); +}); + +const delete_template = catchAsync(async (req, res) => { + const result = await template_service.delete_template_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "template deleted successfully.", + data: result, + meta: {}, + }); +}); + +export const template_controller = { + get_all_template, + get_single_template, + create_template, + update_template, + delete_template, +}; diff --git a/src/app/modules/template/template.route.ts b/src/app/modules/template/template.route.ts new file mode 100644 index 0000000..352af4e --- /dev/null +++ b/src/app/modules/template/template.route.ts @@ -0,0 +1,22 @@ +import { Router } from "express"; +import RequestValidator from "../../middlewares/request_validator.js"; +import { template_controller } from "./template.controller.js"; +import { template_validations } from "./template.validation.js"; + +const router = Router(); + +router.get("/", template_controller.get_all_template); +router.post( + "/", + RequestValidator(template_validations.create_template), + template_controller.create_template, +); +router.get("/:id", template_controller.get_single_template); +router.patch( + "/:id", + RequestValidator(template_validations.update_template), + template_controller.update_template, +); +router.delete("/:id", template_controller.delete_template); + +export default router; diff --git a/src/app/modules/template/template.service.ts b/src/app/modules/template/template.service.ts new file mode 100644 index 0000000..3654585 --- /dev/null +++ b/src/app/modules/template/template.service.ts @@ -0,0 +1,46 @@ +import { Request } from "express"; +import { prisma } from "../../lib/prisma.js"; + +const get_all_template_from_db = async (req: Request) => { + // define your own login here + const result = await prisma.template.findMany(); + return result; +}; + +const get_single_template_from_db = async (req: Request) => { + // define your own login here + const { id } = req.params; + const result = await prisma.template.findUnique({ where: { id } }); + return result; +}; + +const create_template_into_db = async (req: Request) => { + // define your own login here + const result = await prisma.template.create({ data: req.body }); + return result; +}; + +const update_template_into_db = async (req: Request) => { + // define your own login here + const { id } = req.params; + const result = await prisma.template.update({ + where: { id }, + data: req.body, + }); + return result; +}; + +const delete_template_from_db = async (req: Request) => { + // define your own login here + const { id } = req.params; + const result = await prisma.template.delete({ where: { id } }); + return result; +}; + +export const template_service = { + get_all_template_from_db, + get_single_template_from_db, + create_template_into_db, + update_template_into_db, + delete_template_from_db, +}; diff --git a/src/app/modules/template/template.swagger.ts b/src/app/modules/template/template.swagger.ts new file mode 100644 index 0000000..d315cf2 --- /dev/null +++ b/src/app/modules/template/template.swagger.ts @@ -0,0 +1,106 @@ +export const templateSwaggerDocs = { + "/api/template": { + post: { + tags: ["template"], + summary: "Create new template", + description: "", + requestBody: { + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 201: { description: "template created successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + get: { + tags: ["template"], + summary: "Get all template", + description: "", + parameters: [ + { + name: "page", + in: "query", + required: false, + schema: { type: "number" }, + }, + { + name: "limit", + in: "query", + required: false, + schema: { type: "number" }, + }, + ], + responses: { + 200: { description: "template fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, + + "/api/template/{id}": { + get: { + tags: ["template"], + summary: "Get single template", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "template fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + patch: { + tags: ["template"], + summary: "Update template", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + requestBody: { + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 200: { description: "template updated successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + delete: { + tags: ["template"], + summary: "Delete template", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "template delete successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, +}; diff --git a/src/app/modules/template/template.validation.ts b/src/app/modules/template/template.validation.ts new file mode 100644 index 0000000..53ba562 --- /dev/null +++ b/src/app/modules/template/template.validation.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +const create_template = z.object({}); +const update_template = z.object({}); + +export const template_validations = { + create_template, + update_template, +}; diff --git a/src/routes.ts b/src/routes.ts index a7ac1a2..faf8148 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -4,10 +4,12 @@ import orderRoute from "./app/modules/order/order.route.js"; import planRoute from "./app/modules/plan/plan.route.js"; import profileRoute from "./app/modules/profile/profile.route.js"; import supportRoute from "./app/modules/support/support.route.js"; +import templateRoute from "./app/modules/template/template.route"; const appRouter = Router(); const moduleRoutes = [ + { path: "/template", route: templateRoute }, { path: "/order", route: orderRoute }, { path: "/support", route: supportRoute }, { path: "/plan", route: planRoute }, diff --git a/src/swaggerOptions.ts b/src/swaggerOptions.ts index 93859d5..3aa0273 100644 --- a/src/swaggerOptions.ts +++ b/src/swaggerOptions.ts @@ -6,6 +6,7 @@ import { orderSwaggerDocs } from "./app/modules/order/order.swagger.js"; import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js"; import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js"; import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js"; +import { templateSwaggerDocs } from "./app/modules/template/template.swagger"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -24,6 +25,7 @@ export const swaggerOptions = { ...orderSwaggerDocs, ...profileSwaggerDocs, ...supportSwaggerDocs, + ...templateSwaggerDocs, }, servers: configs.env === "production" -- 2.52.0 From b09fdfc2554c05cee2323d8e77982055b5f8f879 Mon Sep 17 00:00:00 2001 From: Md Sharafat Hassain Binoy Date: Tue, 28 Apr 2026 00:29:01 +0600 Subject: [PATCH 02/11] Template-API's : create tamplate and also add the get all template and get single templates --- src/app/modules/template/template.service.ts | 109 +++++++++++++++++- src/app/modules/template/template.swagger.ts | 93 ++++++++++++++- .../modules/template/template.validation.ts | 80 ++++++++++++- 3 files changed, 274 insertions(+), 8 deletions(-) diff --git a/src/app/modules/template/template.service.ts b/src/app/modules/template/template.service.ts index 3654585..4b4be06 100644 --- a/src/app/modules/template/template.service.ts +++ b/src/app/modules/template/template.service.ts @@ -3,26 +3,123 @@ import { prisma } from "../../lib/prisma.js"; const get_all_template_from_db = async (req: Request) => { // define your own login here - const result = await prisma.template.findMany(); + const result = await prisma.template.findMany({}); return result; }; const get_single_template_from_db = async (req: Request) => { // define your own login here - const { id } = req.params; - const result = await prisma.template.findUnique({ where: { id } }); + const { id } = req.params as { id: string }; + const result = await prisma.template.findUnique({ + where: { id }, + select: { + id: true, + language: true, + deliveryCharge: true, + banner: true, + address: true, + ingredient: true, + instruction: true, + faq: true, + tips: true, + priceCombo: true, + product: true, + }, + }); return result; }; const create_template_into_db = async (req: Request) => { // define your own login here - const result = await prisma.template.create({ data: req.body }); + const payload = req.body; + console.log(payload); + const result = await prisma.template.create({ + data: { + language: payload.language, + deliveryCharge: payload.deliveryCharge, + + banner: { + create: payload.banner, + }, + + address: { + create: payload.address, + }, + + ingredient: { + create: { + isVisible: payload.ingredient.isVisible, + options: { + create: payload.ingredient.options, + }, + }, + }, + + instruction: { + create: { + isVisible: payload.instruction.isVisible, + instBanner: payload.instruction.instBanner, + options: { + create: payload.instruction.options, + }, + }, + }, + + faq: { + create: { + isVisible: payload.faq.isVisible, + options: { + create: payload.faq.options, + }, + }, + }, + + tips: { + create: { + isVisible: payload.tips.isVisible, + tipsBanner: payload.tips.tipsBanner, + options: { + create: payload.tips.options, + }, + }, + }, + + priceCombo: { + create: { + isVisible: payload.priceCombo.isVisible, + options: { + create: payload.priceCombo.options, + }, + }, + }, + + product: { + create: { + isVisible: payload.product.isVisible, + price: payload.product.price, + discount: payload.product.discount, + productName: payload.product.productName, + }, + }, + }, + + include: { + banner: true, + address: true, + ingredient: { include: { options: true } }, + instruction: { include: { options: true } }, + faq: { include: { options: true } }, + tips: { include: { options: true } }, + priceCombo: { include: { options: true } }, + product: true, + }, + }); return result; }; const update_template_into_db = async (req: Request) => { // define your own login here - const { id } = req.params; + const { id } = req.params as { id: string }; const result = await prisma.template.update({ where: { id }, data: req.body, @@ -32,7 +129,7 @@ const update_template_into_db = async (req: Request) => { const delete_template_from_db = async (req: Request) => { // define your own login here - const { id } = req.params; + const { id } = req.params as { id: string }; const result = await prisma.template.delete({ where: { id } }); return result; }; diff --git a/src/app/modules/template/template.swagger.ts b/src/app/modules/template/template.swagger.ts index d315cf2..9fcd93b 100644 --- a/src/app/modules/template/template.swagger.ts +++ b/src/app/modules/template/template.swagger.ts @@ -8,7 +8,98 @@ export const templateSwaggerDocs = { required: true, content: { "application/json": { - example: JSON.stringify({}), // put your request body + example: JSON.stringify({ + language: "en", + deliveryCharge: "60", + banner: { + isVisible: true, + bannerTitle: "Delicious Homemade Food", + bannerDesc: + "Fresh, healthy and tasty meals delivered to your door.", + bannerImage: "https://example.com/banner.jpg", + }, + address: { + isVisible: true, + phoneNumber: "+8801712345678", + shopLocation: "Dhaka, Bangladesh", + shopEmail: "foodshop@example.com", + }, + ingredient: { + isVisible: true, + options: [ + { + ingrImg: "https://example.com/tomato.jpg", + ingrTitle: "Tomato", + ingrDes: "Fresh organic tomatoes", + }, + { + ingrImg: "https://example.com/chicken.jpg", + ingrTitle: "Chicken", + ingrDes: "Premium quality chicken", + }, + ], + }, + instruction: { + isVisible: true, + instBanner: "https://example.com/instruction-banner.jpg", + options: [ + { + hint: "Step 1", + detail: "Wash all ingredients properly", + }, + { + hint: "Step 2", + detail: "Cook on medium heat for 20 minutes", + }, + ], + }, + faq: { + isVisible: true, + options: [ + { + index: 1, + text: "Is the food fresh?", + }, + { + index: 2, + text: "Do you offer home delivery?", + }, + ], + }, + tips: { + isVisible: true, + tipsBanner: "https://example.com/tips-banner.jpg", + options: [ + { + index: 1, + text: "Use fresh ingredients for best taste", + }, + { + index: 2, + text: "Serve hot for better flavor", + }, + ], + }, + priceCombo: { + isVisible: true, + options: [ + { + quantity: "1", + price: "120", + }, + { + quantity: "2", + price: "220", + }, + ], + }, + product: { + isVisible: true, + price: "120", + discount: 10, + productName: "Chicken Burger", + }, + }), // put your request body }, }, }, diff --git a/src/app/modules/template/template.validation.ts b/src/app/modules/template/template.validation.ts index 53ba562..0243549 100644 --- a/src/app/modules/template/template.validation.ts +++ b/src/app/modules/template/template.validation.ts @@ -1,6 +1,84 @@ import { z } from "zod"; -const create_template = z.object({}); +// Template Options that we need to use for validation. + +// Ingredient Option +const ingredientOptionSchema = z.object({ + ingrImg: z.string().url().or(z.string()), + ingrTitle: z.string().min(1), + ingrDes: z.string().min(1), +}); + +// Instruction Option +const instructionOptionSchema = z.object({ + hint: z.string().min(1), + detail: z.string().min(1), +}); + +// FAQ Option +const faqOptionSchema = z.object({ + index: z.number(), + text: z.string().min(1), +}); + +// Tips Option +const tipsOptionSchema = z.object({ + index: z.number(), + text: z.string().min(1), +}); + +// Price Option +const priceOptionSchema = z.object({ + quantity: z.string().min(1), + price: z.string().min(1), +}); + + +// Create the main template schema validation +const create_template = z.object({ + language: z.string().min(1), + deliveryCharge: z.string().min(1), + banner: z.object({ + isVisible: z.boolean(), + bannerTitle: z.string().min(1), + bannerDesc: z.string().min(1), + bannerImage: z.string(), + }), + address: z.object({ + isVisible: z.boolean(), + phoneNumber: z.string().min(1), + shopLocation: z.string().min(1), + shopEmail: z.string().email(), + }), + ingredient: z.object({ + isVisible: z.boolean(), + options: z.array(ingredientOptionSchema).min(1), + }), + instruction: z.object({ + isVisible: z.boolean(), + instBanner: z.string(), + options: z.array(instructionOptionSchema).min(1), + }), + faq: z.object({ + isVisible: z.boolean(), + options: z.array(faqOptionSchema).min(1), + }), + tips: z.object({ + isVisible: z.boolean(), + tipsBanner: z.string(), + options: z.array(tipsOptionSchema).min(1), + }), + priceCombo: z.object({ + isVisible: z.boolean(), + options: z.array(priceOptionSchema).min(1), + }), + product: z.object({ + isVisible: z.boolean(), + price: z.string().min(1), + discount: z.number().min(0), + productName: z.string().min(1), + }), +}); const update_template = z.object({}); export const template_validations = { -- 2.52.0 From d2b320f3b1dbdcfb4a69de87a1ed47afb40df420 Mon Sep 17 00:00:00 2001 From: Md Sharafat Hassain Binoy Date: Thu, 30 Apr 2026 21:26:18 +0600 Subject: [PATCH 03/11] Change the api and add some new feature --- src/app/modules/order/order.service.ts | 8 + src/app/modules/plan/plan.service.ts | 11 +- .../modules/statictics/statictics.swagger.ts | 138 ++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/app/modules/statictics/statictics.swagger.ts diff --git a/src/app/modules/order/order.service.ts b/src/app/modules/order/order.service.ts index 1285906..e554f37 100644 --- a/src/app/modules/order/order.service.ts +++ b/src/app/modules/order/order.service.ts @@ -93,6 +93,14 @@ const get_all_order_from_db = async (req: Request) => { where: { AND: andCondition, }, + select: { + id: true, + customerName: true, + productQuantity: true, + productPrice: true, + status: true, + createdAt: true, + }, orderBy: { [sortBy as string]: sortOrder, }, diff --git a/src/app/modules/plan/plan.service.ts b/src/app/modules/plan/plan.service.ts index 4d351c0..d550a8b 100644 --- a/src/app/modules/plan/plan.service.ts +++ b/src/app/modules/plan/plan.service.ts @@ -5,7 +5,16 @@ import { AppError } from "../../utils/app_error.js"; const get_all_plan_from_db = async (req: Request) => { // define your own login here - const result = await prisma.plan.findMany(); + const result = await prisma.plan.findMany({ + select:{ + planName: true, + price: true, + planType: true, + planDesc: true, + planFeatures: true, + + } + }); return result; }; diff --git a/src/app/modules/statictics/statictics.swagger.ts b/src/app/modules/statictics/statictics.swagger.ts new file mode 100644 index 0000000..16a7ef0 --- /dev/null +++ b/src/app/modules/statictics/statictics.swagger.ts @@ -0,0 +1,138 @@ + +export const staticticsSwaggerDocs = { + "/api/statictics": { + post: { + tags: ["statictics"], + summary: "Create new statictics", + description: "", + requestBody: { + + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 201: { description: "statictics created successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + get: { + tags: ["statictics"], + summary: "Get all statictics", + description: "", + parameters: [ + { + name: "page", + in: "query", + required: false, + schema: { type: "number" }, + }, + { + name: "limit", + in: "query", + required: false, + schema: { type: "number" }, + }, + ], + responses: { + 200: { description: "statictics fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, + "/api/statictics/seller": { + get: { + tags: ["statistics"], + summary: "Get seller statistics", + description: "Fetch seller dashboard stats (7d, 30d, all)", + + parameters: [ + { + name: "range", + in: "query", + required: false, + schema: { + type: "string", + enum: ["7d", "30d", "all"], + default: "7d", + }, + description: "Time range for statistics", + }, + ], + + responses: { + 200: { + description: "Statistics fetched successfully", + }, + 401: { + description: "Unauthorized", + }, + }, + }, + }, + + "/api/statictics/{id}": { + get: { + tags: ["statictics"], + summary: "Get single statictics", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "statictics fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + patch: { + tags: ["statictics"], + summary: "Update statictics", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + requestBody: { + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 200: { description: "statictics updated successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + delete: { + tags: ["statictics"], + summary: "Delete statictics", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "statictics delete successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, +}; -- 2.52.0 From 1abecc9b8f2c7e7d510c45d67c422aa15c8711cd Mon Sep 17 00:00:00 2001 From: sharafat Date: Sun, 24 May 2026 00:17:16 +0600 Subject: [PATCH 04/11] Update:PROFILE API's and create get users api's with pagination --- .../20260523173211_edit_profile/migration.sql | 14 +++ .../migration.sql | 2 + prisma/schema/profile.schema.prisma | 17 ++- prisma/schema/users.prisma | 7 ++ src/app/modules/profile/profile.swagger.ts | 2 +- src/app/modules/profile/profile.validation.ts | 11 +- src/app/modules/users/users.controller.ts | 69 +++++++++++ src/app/modules/users/users.route.ts | 24 ++++ src/app/modules/users/users.service.ts | 65 +++++++++++ src/app/modules/users/users.swagger.ts | 110 ++++++++++++++++++ src/app/modules/users/users.validation.ts | 10 ++ src/routes.ts | 2 + src/swaggerOptions.ts | 2 + 13 files changed, 327 insertions(+), 8 deletions(-) create mode 100644 prisma/migrations/20260523173211_edit_profile/migration.sql create mode 100644 prisma/migrations/20260523174545_edit_the_profile_status/migration.sql create mode 100644 prisma/schema/users.prisma create mode 100644 src/app/modules/users/users.controller.ts create mode 100644 src/app/modules/users/users.route.ts create mode 100644 src/app/modules/users/users.service.ts create mode 100644 src/app/modules/users/users.swagger.ts create mode 100644 src/app/modules/users/users.validation.ts diff --git a/prisma/migrations/20260523173211_edit_profile/migration.sql b/prisma/migrations/20260523173211_edit_profile/migration.sql new file mode 100644 index 0000000..7f77fa8 --- /dev/null +++ b/prisma/migrations/20260523173211_edit_profile/migration.sql @@ -0,0 +1,14 @@ +-- CreateEnum +CREATE TYPE "ShopStatus" AS ENUM ('ACTIVE', 'SUSPENDED', 'DELETED'); + +-- AlterTable +ALTER TABLE "Profile" ADD COLUMN "status" "ShopStatus" NOT NULL DEFAULT 'ACTIVE'; + +-- CreateTable +CREATE TABLE "Users" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Users_pkey" PRIMARY KEY ("id") +); diff --git a/prisma/migrations/20260523174545_edit_the_profile_status/migration.sql b/prisma/migrations/20260523174545_edit_the_profile_status/migration.sql new file mode 100644 index 0000000..b45a2dc --- /dev/null +++ b/prisma/migrations/20260523174545_edit_the_profile_status/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "ShopStatus" ADD VALUE 'INACTIVE'; diff --git a/prisma/schema/profile.schema.prisma b/prisma/schema/profile.schema.prisma index b5959a9..26ef467 100644 --- a/prisma/schema/profile.schema.prisma +++ b/prisma/schema/profile.schema.prisma @@ -1,14 +1,19 @@ +enum ShopStatus { + ACTIVE + SUSPENDED + DELETED + INACTIVE +} + model Profile { - id String @id @default(uuid()) - accountId String @unique - account Account @relation(fields: [accountId], references: [id], onDelete: Cascade) + id String @id @default(uuid()) + accountId String @unique + account Account @relation(fields: [accountId], references: [id], onDelete: Cascade) shopName String shopLogo String? contactNumber String? shopAddress String? shopMapLocation String? shopCategory String? - + status ShopStatus @default(ACTIVE) } - - diff --git a/prisma/schema/users.prisma b/prisma/schema/users.prisma new file mode 100644 index 0000000..f5a0e8c --- /dev/null +++ b/prisma/schema/users.prisma @@ -0,0 +1,7 @@ + +model Users { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + \ No newline at end of file diff --git a/src/app/modules/profile/profile.swagger.ts b/src/app/modules/profile/profile.swagger.ts index 5a93aee..4494f8d 100644 --- a/src/app/modules/profile/profile.swagger.ts +++ b/src/app/modules/profile/profile.swagger.ts @@ -13,7 +13,7 @@ export const profileSwaggerDocs = { data: { type: "object", properties: { - fullName: { type: "string" }, + shopName: { type: "string" }, }, }, file: { diff --git a/src/app/modules/profile/profile.validation.ts b/src/app/modules/profile/profile.validation.ts index b7ffb04..eb604d3 100644 --- a/src/app/modules/profile/profile.validation.ts +++ b/src/app/modules/profile/profile.validation.ts @@ -1,6 +1,15 @@ import { z } from "zod"; const update_profile = z.object({ - fullName: z.string().optional(), + shopName: z.string().optional(), + shopAddress: z.string().optional(), + shopPhone: z.string().optional(), + shopLocation: z.string().optional(), + shopImage: z.string().optional(), + shopMapLocation: z.string().optional(), + contactNumber: z.string().optional(), + shopCategory: z.string().optional(), + + }); export const profile_validations = { diff --git a/src/app/modules/users/users.controller.ts b/src/app/modules/users/users.controller.ts new file mode 100644 index 0000000..d134055 --- /dev/null +++ b/src/app/modules/users/users.controller.ts @@ -0,0 +1,69 @@ +import catchAsync from "../../utils/catch_async.js"; +import manageResponse from "../../utils/manage_response.js"; +import { users_service } from "./users.service.js"; + + + +const get_all_users = catchAsync(async (req, res) => { + const result = await users_service.get_all_users_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "All users fetched successfully.", + data: result, + meta: {}, + }); +}); + +const get_single_users = catchAsync(async (req, res) => { + const result = await users_service.get_single_users_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "Single users fetched successfully.", + data: result, + meta: {}, + }); +}); + +const create_users = catchAsync(async (req, res) => { + const result = await users_service.create_users_into_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "users created successfully.", + data: result, + meta: {}, + }); +}); + +const update_users = catchAsync(async (req, res) => { + const result = await users_service.update_users_into_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "users updated successfully.", + data: result, + meta: {}, + }); +}); + +const delete_users = catchAsync(async (req, res) => { + const result = await users_service.delete_users_from_db(req); + manageResponse(res, { + success: true, + statusCode: 200, + message: "users deleted successfully.", + data: result, + meta: {}, + }); +}); + +export const users_controller = { + get_all_users, + get_single_users, + create_users, + update_users, + delete_users, +}; + \ No newline at end of file diff --git a/src/app/modules/users/users.route.ts b/src/app/modules/users/users.route.ts new file mode 100644 index 0000000..be8e7ab --- /dev/null +++ b/src/app/modules/users/users.route.ts @@ -0,0 +1,24 @@ + + import { Router } from "express"; +import { users_controller } from "./users.controller.js"; +import { users_validations } from "./users.validation.js"; +import RequestValidator from "../../middlewares/request_validator.js"; + +const router = Router(); + +router.get("/", users_controller.get_all_users); +router.post( + "/", + RequestValidator(users_validations.create_users), + users_controller.create_users, +); +router.get("/:id", users_controller.get_single_users); +router.patch( + "/:id", + RequestValidator(users_validations.update_users), + users_controller.update_users, +); +router.delete("/:id", users_controller.delete_users); + +export default router; + \ No newline at end of file diff --git a/src/app/modules/users/users.service.ts b/src/app/modules/users/users.service.ts new file mode 100644 index 0000000..2d135dc --- /dev/null +++ b/src/app/modules/users/users.service.ts @@ -0,0 +1,65 @@ + +import { Request } from "express"; +import { prisma } from "../../lib/prisma.js"; +import paginationHelper from "../../utils/pagination_helper.js"; + +const get_all_users_from_db = async (req: Request) => { + const {page,skip,limit}=paginationHelper(req.query); + + + // define your own login here + const result = await prisma.profile.findMany({ + take:limit, + skip, + select:{ + account:{ + select:{ + isSubscribe:true, + email:true, + + } + }, + shopName:true, + id:true, + status:true + + } + }); + return result; +}; + +const get_single_users_from_db = async (req: Request) => { + // define your own login here + const { id } = req.params as { id: string }; + const result = await prisma.account.findUnique({where:{id}}); + return result; +}; + +const create_users_into_db = async (req: Request) => { + // define your own login here + const result = await prisma.account.create({data:req.body}); + return result; +}; + +const update_users_into_db = async (req: Request) => { + // define your own login here + const { id } = req.params as { id: string }; + const result = await prisma.account.update({where:{id},data:req.body}); + return result; +}; + +const delete_users_from_db = async (req: Request) => { + // define your own login here + const { id } = req.params as { id: string }; + const result = await prisma.account.delete({where:{id}}); + return result; +}; + +export const users_service = { + get_all_users_from_db, + get_single_users_from_db, + create_users_into_db, + update_users_into_db, + delete_users_from_db, +}; + \ No newline at end of file diff --git a/src/app/modules/users/users.swagger.ts b/src/app/modules/users/users.swagger.ts new file mode 100644 index 0000000..a951986 --- /dev/null +++ b/src/app/modules/users/users.swagger.ts @@ -0,0 +1,110 @@ + + export const usersSwaggerDocs = { + "/api/users": { + post: { + tags: ["users"], + summary: "Create new users", + description: "", + requestBody: { + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 201: { description: "users created successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + get: { + tags: ["users"], + summary: "Get all users", + description: "", + parameters: [ + { + name: "page", + in: "query", + required: false, + schema: { type: "number" }, + }, + { + name: "limit", + in: "query", + required: false, + schema: { type: "number" }, + }, + ], + responses: { + 200: { description: "users fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, + + "/api/users/{id}": { + get: { + tags: ["users"], + summary: "Get single users", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "users fetched successfully" }, + 401: { description: "unauthorized" }, + }, + }, + patch: { + tags: ["users"], + summary: "Update users", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + requestBody: { + required: true, + content: { + "application/json": { + example: JSON.stringify({}), // put your request body + }, + }, + }, + responses: { + 200: { description: "users updated successfully" }, + 500: { description: "Validation error or internal server error" }, + }, + }, + delete: { + tags: ["users"], + summary: "Delete users", + description: "", + parameters: [ + { + name: "id", + in: "path", + required: true, + schema: { type: "string" }, + }, + ], + responses: { + 200: { description: "users delete successfully" }, + 401: { description: "unauthorized" }, + }, + }, + }, +}; + + + \ No newline at end of file diff --git a/src/app/modules/users/users.validation.ts b/src/app/modules/users/users.validation.ts new file mode 100644 index 0000000..2424e36 --- /dev/null +++ b/src/app/modules/users/users.validation.ts @@ -0,0 +1,10 @@ + +import { z } from "zod"; + +const create_users = z.object({}); +const update_users = z.object({}); + +export const users_validations = { + create_users, + update_users, +}; diff --git a/src/routes.ts b/src/routes.ts index faf8148..e873c17 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -5,10 +5,12 @@ import planRoute from "./app/modules/plan/plan.route.js"; import profileRoute from "./app/modules/profile/profile.route.js"; import supportRoute from "./app/modules/support/support.route.js"; import templateRoute from "./app/modules/template/template.route"; +import usersRoute from "./app/modules/users/users.route"; const appRouter = Router(); const moduleRoutes = [ + { path: "/users", route: usersRoute }, { path: "/template", route: templateRoute }, { path: "/order", route: orderRoute }, { path: "/support", route: supportRoute }, diff --git a/src/swaggerOptions.ts b/src/swaggerOptions.ts index 3aa0273..34fd8ba 100644 --- a/src/swaggerOptions.ts +++ b/src/swaggerOptions.ts @@ -7,6 +7,7 @@ import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js"; import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js"; import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js"; import { templateSwaggerDocs } from "./app/modules/template/template.swagger"; +import { usersSwaggerDocs } from "./app/modules/users/users.swagger"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -26,6 +27,7 @@ export const swaggerOptions = { ...profileSwaggerDocs, ...supportSwaggerDocs, ...templateSwaggerDocs, + ...usersSwaggerDocs, }, servers: configs.env === "production" -- 2.52.0 From c05266a522738db7e09efc5a4f7b61aefd797728 Mon Sep 17 00:00:00 2001 From: sharafat Date: Sun, 24 May 2026 23:37:13 +0600 Subject: [PATCH 05/11] USER API's resolve the issues --- src/app/modules/users/users.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/modules/users/users.service.ts b/src/app/modules/users/users.service.ts index 2d135dc..c45dd3e 100644 --- a/src/app/modules/users/users.service.ts +++ b/src/app/modules/users/users.service.ts @@ -25,7 +25,8 @@ const get_all_users_from_db = async (req: Request) => { } }); - return result; + const usersCount = await prisma.profile.count(); + return{ result,usersCount,page,limit,skip}; }; const get_single_users_from_db = async (req: Request) => { -- 2.52.0 From 0a8fe573ae07b4fc176fa0150cedb32dc49fa305 Mon Sep 17 00:00:00 2001 From: abumahid Date: Wed, 17 Jun 2026 20:15:51 +0600 Subject: [PATCH 06/11] Remove dist folder from repository --- dist/app.js | 37 -- dist/app/configs/index.js | 26 -- dist/app/errors/zodError.js | 15 - dist/app/lib/prisma.js | 8 - dist/app/middlewares/auth.js | 23 -- dist/app/middlewares/global_error_handler.js | 47 --- dist/app/middlewares/not_found_api.js | 8 - dist/app/middlewares/request_validator.js | 12 - dist/app/middlewares/uploader.js | 12 - .../app/modules/account/account.controller.js | 101 ----- dist/app/modules/account/account.route.js | 16 - dist/app/modules/account/account.service.js | 371 ------------------ dist/app/modules/account/account.swagger.js | 187 --------- .../app/modules/account/account.validation.js | 37 -- dist/app/modules/order/order.controller.js | 60 --- dist/app/modules/order/order.route.js | 12 - dist/app/modules/order/order.service.js | 163 -------- dist/app/modules/order/order.swagger.js | 165 -------- dist/app/modules/order/order.validation.js | 19 - dist/app/modules/plan/plan.controller.js | 60 --- dist/app/modules/plan/plan.route.js | 12 - dist/app/modules/plan/plan.service.js | 68 ---- dist/app/modules/plan/plan.swagger.js | 125 ------ dist/app/modules/plan/plan.validation.js | 33 -- .../app/modules/profile/profile.controller.js | 15 - dist/app/modules/profile/profile.route.js | 12 - dist/app/modules/profile/profile.service.js | 23 -- dist/app/modules/profile/profile.swagger.js | 34 -- .../app/modules/profile/profile.validation.js | 7 - .../app/modules/support/support.controller.js | 80 ---- dist/app/modules/support/support.route.js | 12 - dist/app/modules/support/support.service.js | 100 ----- dist/app/modules/support/support.swagger.js | 109 ----- .../app/modules/support/support.validation.js | 28 -- dist/app/queues/connection.js | 7 - dist/app/queues/email/email.processor.js | 14 - dist/app/queues/email/email.queue.js | 6 - dist/app/queues/email/email.worker.js | 7 - .../email/order/order.email.processor.js | 12 - .../queues/email/order/order.email.queue.js | 5 - .../queues/email/order/order.email.worker.js | 7 - dist/app/queues/worker.js | 3 - dist/app/templates/otpTemplate.js | 80 ---- dist/app/utils/JWT.js | 15 - dist/app/utils/app_error.js | 13 - dist/app/utils/catch_async.js | 11 - dist/app/utils/cloudinary.js | 23 -- dist/app/utils/mail_sender.js | 113 ------ dist/app/utils/manage_response.js | 9 - dist/app/utils/otpGenerator.js | 23 -- dist/app/utils/pagination_helper.js | 15 - dist/routes.js | 16 - dist/server.js | 19 - dist/swaggerOptions.js | 48 --- 54 files changed, 2483 deletions(-) delete mode 100644 dist/app.js delete mode 100644 dist/app/configs/index.js delete mode 100644 dist/app/errors/zodError.js delete mode 100644 dist/app/lib/prisma.js delete mode 100644 dist/app/middlewares/auth.js delete mode 100644 dist/app/middlewares/global_error_handler.js delete mode 100644 dist/app/middlewares/not_found_api.js delete mode 100644 dist/app/middlewares/request_validator.js delete mode 100644 dist/app/middlewares/uploader.js delete mode 100644 dist/app/modules/account/account.controller.js delete mode 100644 dist/app/modules/account/account.route.js delete mode 100644 dist/app/modules/account/account.service.js delete mode 100644 dist/app/modules/account/account.swagger.js delete mode 100644 dist/app/modules/account/account.validation.js delete mode 100644 dist/app/modules/order/order.controller.js delete mode 100644 dist/app/modules/order/order.route.js delete mode 100644 dist/app/modules/order/order.service.js delete mode 100644 dist/app/modules/order/order.swagger.js delete mode 100644 dist/app/modules/order/order.validation.js delete mode 100644 dist/app/modules/plan/plan.controller.js delete mode 100644 dist/app/modules/plan/plan.route.js delete mode 100644 dist/app/modules/plan/plan.service.js delete mode 100644 dist/app/modules/plan/plan.swagger.js delete mode 100644 dist/app/modules/plan/plan.validation.js delete mode 100644 dist/app/modules/profile/profile.controller.js delete mode 100644 dist/app/modules/profile/profile.route.js delete mode 100644 dist/app/modules/profile/profile.service.js delete mode 100644 dist/app/modules/profile/profile.swagger.js delete mode 100644 dist/app/modules/profile/profile.validation.js delete mode 100644 dist/app/modules/support/support.controller.js delete mode 100644 dist/app/modules/support/support.route.js delete mode 100644 dist/app/modules/support/support.service.js delete mode 100644 dist/app/modules/support/support.swagger.js delete mode 100644 dist/app/modules/support/support.validation.js delete mode 100644 dist/app/queues/connection.js delete mode 100644 dist/app/queues/email/email.processor.js delete mode 100644 dist/app/queues/email/email.queue.js delete mode 100644 dist/app/queues/email/email.worker.js delete mode 100644 dist/app/queues/email/order/order.email.processor.js delete mode 100644 dist/app/queues/email/order/order.email.queue.js delete mode 100644 dist/app/queues/email/order/order.email.worker.js delete mode 100644 dist/app/queues/worker.js delete mode 100644 dist/app/templates/otpTemplate.js delete mode 100644 dist/app/utils/JWT.js delete mode 100644 dist/app/utils/app_error.js delete mode 100644 dist/app/utils/catch_async.js delete mode 100644 dist/app/utils/cloudinary.js delete mode 100644 dist/app/utils/mail_sender.js delete mode 100644 dist/app/utils/manage_response.js delete mode 100644 dist/app/utils/otpGenerator.js delete mode 100644 dist/app/utils/pagination_helper.js delete mode 100644 dist/routes.js delete mode 100644 dist/server.js delete mode 100644 dist/swaggerOptions.js diff --git a/dist/app.js b/dist/app.js deleted file mode 100644 index 2715737..0000000 --- a/dist/app.js +++ /dev/null @@ -1,37 +0,0 @@ -import cookieParser from 'cookie-parser'; -import cors from 'cors'; -import express from 'express'; -import swaggerJSDoc from 'swagger-jsdoc'; -import swaggerUi from "swagger-ui-express"; -import globalErrorHandler from './app/middlewares/global_error_handler.js'; -import notFound from './app/middlewares/not_found_api.js'; -import appRouter from './routes.js'; -import { swaggerOptions } from './swaggerOptions.js'; -// define app -const app = express(); -const swaggerSpec = swaggerJSDoc(swaggerOptions); -app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); -// middleware -app.use(cors({ - origin: ["http://localhost:5173"], - methods: ["GET", "POST", "PATCH", "DELETE", "PUT"], - credentials: true -})); -app.use(express.json({ limit: "100mb" })); -app.use(express.raw()); -app.use(cookieParser()); -app.use(express.urlencoded({ extended: true })); -app.use("/api", appRouter); -// stating point -app.get('/', (req, res) => { - res.status(200).json({ - status: 'success', - message: 'Server is running successful !!', - data: null, - }); -}); -// global error handler -app.use(globalErrorHandler); -app.use(notFound); -// export app -export default app; diff --git a/dist/app/configs/index.js b/dist/app/configs/index.js deleted file mode 100644 index 8ede15d..0000000 --- a/dist/app/configs/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import "dotenv/config"; -export const configs = { - port: process.env.PORT, - env: process.env.NODE_ENV, - db_url: process.env.DATABASE_URL, - jwt: { - access_token: process.env.ACCESS_TOKEN, - refresh_token: process.env.REFRESH_TOKEN, - access_expires: process.env.ACCESS_EXPIRES, - refresh_expires: process.env.REFRESH_EXPIRES, - reset_secret: process.env.RESET_SECRET, - reset_expires: process.env.RESET_EXPIRES, - front_end_url: process.env.FRONT_END_URL, - verified_token: process.env.VERIFIED_TOKEN, - }, - email: { - app_email: process.env.APP_USER_EMAIL, - app_password: process.env.APP_PASSWORD, - }, - cloudinary: { - cloud_name: process.env.CLOUD_NAME, - cloud_api_key: process.env.CLOUD_API_KEY, - cloud_api_secret: process.env.CLOUD_API_SECRET, - }, - redis_url: process.env.REDIS_URL, -}; diff --git a/dist/app/errors/zodError.js b/dist/app/errors/zodError.js deleted file mode 100644 index 77da904..0000000 --- a/dist/app/errors/zodError.js +++ /dev/null @@ -1,15 +0,0 @@ -const handleZodError = (err) => { - const errorSources = err.issues.map((issue) => { - return { - path: issue?.path[issue.path.length - 1], - message: issue.message - }; - }); - const statusCode = 400; - return { - statusCode, - message: 'Validation Error', - errorSources - }; -}; -export default handleZodError; diff --git a/dist/app/lib/prisma.js b/dist/app/lib/prisma.js deleted file mode 100644 index e9b8c5b..0000000 --- a/dist/app/lib/prisma.js +++ /dev/null @@ -1,8 +0,0 @@ -import { PrismaPg } from "@prisma/adapter-pg"; -import pkg from "@prisma/client"; -import "dotenv/config"; -const { PrismaClient } = pkg; -const connectionString = `${process.env.DATABASE_URL}`; -const adapter = new PrismaPg({ connectionString }); -const prisma = new PrismaClient({ adapter }); -export { prisma }; diff --git a/dist/app/middlewares/auth.js b/dist/app/middlewares/auth.js deleted file mode 100644 index 20cd2c0..0000000 --- a/dist/app/middlewares/auth.js +++ /dev/null @@ -1,23 +0,0 @@ -import { configs } from "../configs/index.js"; -import { AppError } from "../utils/app_error.js"; -import { jwtHelpers } from "../utils/JWT.js"; -const auth = (...roles) => { - return async (req, res, next) => { - try { - const token = req.headers.authorization || req.cookies.access_token; - if (!token) { - throw new AppError("You are not authorize!!", 401); - } - const verifiedUser = jwtHelpers.verifyToken(token, configs.jwt.access_token); - if (!roles.length || !roles.includes(verifiedUser.role)) { - throw new AppError("You are not authorize!!", 401); - } - req.user = verifiedUser; - next(); - } - catch (err) { - next(err); - } - }; -}; -export default auth; diff --git a/dist/app/middlewares/global_error_handler.js b/dist/app/middlewares/global_error_handler.js deleted file mode 100644 index c56e5eb..0000000 --- a/dist/app/middlewares/global_error_handler.js +++ /dev/null @@ -1,47 +0,0 @@ -import { ZodError } from "zod"; -import { configs } from "../configs/index.js"; -import handleZodError from "../errors/zodError.js"; -import { AppError } from "../utils/app_error.js"; -const globalErrorHandler = (err, req, res, next) => { - let statusCode = 500; - let message = "Something went wrong!"; - let errorSources = [ - { - path: "", - message: "Something went wrong", - }, - ]; - if (err instanceof ZodError) { - const simplifiedError = handleZodError(err); - statusCode = simplifiedError?.statusCode; - message = simplifiedError?.message; - errorSources = simplifiedError?.errorSources; - } - else if (err instanceof AppError) { - statusCode = err?.statusCode; - message = err.message; - errorSources = [ - { - path: "", - message: err?.message, - }, - ]; - } - else if (err instanceof Error) { - message = err.message; - errorSources = [ - { - path: "", - message: err?.message, - }, - ]; - } - res.status(statusCode).json({ - success: false, - message, - errorSources, - err, - stack: configs.env === "development" ? err?.stack : null, - }); -}; -export default globalErrorHandler; diff --git a/dist/app/middlewares/not_found_api.js b/dist/app/middlewares/not_found_api.js deleted file mode 100644 index ab074e0..0000000 --- a/dist/app/middlewares/not_found_api.js +++ /dev/null @@ -1,8 +0,0 @@ -const notFound = (req, res, next) => { - res.status(404).json({ - message: 'Sorry Route is not found!! 😴😴😴', - success: false, - error: '', - }); -}; -export default notFound; diff --git a/dist/app/middlewares/request_validator.js b/dist/app/middlewares/request_validator.js deleted file mode 100644 index 73024a8..0000000 --- a/dist/app/middlewares/request_validator.js +++ /dev/null @@ -1,12 +0,0 @@ -const RequestValidator = (schema) => { - return async (req, res, next) => { - try { - req.body = await schema.parseAsync(req.body); - next(); - } - catch (err) { - next(err); - } - }; -}; -export default RequestValidator; diff --git a/dist/app/middlewares/uploader.js b/dist/app/middlewares/uploader.js deleted file mode 100644 index da05753..0000000 --- a/dist/app/middlewares/uploader.js +++ /dev/null @@ -1,12 +0,0 @@ -import multer from "multer"; -import path from "path"; -const storage = multer.diskStorage({ - destination: function (req, file, cb) { - cb(null, path.join(process.cwd(), "uploads")); - }, - filename: function (req, file, cb) { - cb(null, file.originalname); - } -}); -const uploader = multer({ storage: storage }); -export default uploader; diff --git a/dist/app/modules/account/account.controller.js b/dist/app/modules/account/account.controller.js deleted file mode 100644 index 964447d..0000000 --- a/dist/app/modules/account/account.controller.js +++ /dev/null @@ -1,101 +0,0 @@ -import { configs } from "../../configs/index.js"; -import catchAsync from "../../utils/catch_async.js"; -import manageResponse from "../../utils/manage_response.js"; -import { account_services } from "./account.service.js"; -const create_account = catchAsync(async (req, res) => { - const result = await account_services.create_account_into_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Account created successfully", - data: result, - }); -}); -const verify_account_using_otp = catchAsync(async (req, res) => { - const result = await account_services.verify_account_using_otp_into_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Otp verification successful", - data: result, - }); -}); -const verify_account_using_link = catchAsync(async (req, res) => { - const result = await account_services.verify_account_using_link_into_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Account verification successful", - data: result, - }); -}); -const login_user = catchAsync(async (req, res) => { - const result = await account_services.login_user_into_db(req); - // set access token into cookie - res.cookie("access_token", result.accessToken, { - secure: configs.env === "production", - httpOnly: true, - }); - manageResponse(res, { - statusCode: 200, - success: true, - message: "User logged in successfully", - data: result, - }); -}); -const get_user_account = catchAsync(async (req, res) => { - const result = await account_services.get_user_account_from_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Account fetched successfully", - data: result, - }); -}); -const change_password = catchAsync(async (req, res) => { - const result = await account_services.change_password_into_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Password Change successfully", - data: result, - }); -}); -const resend_otp_and_verification_link = catchAsync(async (req, res) => { - const result = await account_services.resend_otp_and_verification_link_from_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "OTP reset successfully", - data: result, - }); -}); -const forget_password_generate_reset_token = catchAsync(async (req, res) => { - const result = await account_services.forget_password_generate_reset_token_from_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Password reset successfully", - data: result, - }); -}); -const reset_password_using_token = catchAsync(async (req, res) => { - const result = await account_services.reset_password_using_token_into_db(req); - manageResponse(res, { - statusCode: 200, - success: true, - message: "Password reset successfully", - data: result, - }); -}); -export const account_controller = { - create_account, - login_user, - get_user_account, - change_password, - verify_account_using_otp, - resend_otp_and_verification_link, - verify_account_using_link, - forget_password_generate_reset_token, - reset_password_using_token -}; diff --git a/dist/app/modules/account/account.route.js b/dist/app/modules/account/account.route.js deleted file mode 100644 index 7ac80a0..0000000 --- a/dist/app/modules/account/account.route.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Router } from "express"; -import auth from "../../middlewares/auth.js"; -import RequestValidator from "../../middlewares/request_validator.js"; -import { account_controller } from "./account.controller.js"; -import { account_validation } from "./account.validation.js"; -const accountRouter = Router(); -accountRouter.post("/sign-up", RequestValidator(account_validation.sign_up), account_controller.create_account); -accountRouter.post("/sign-in", RequestValidator(account_validation.sing_in), account_controller.login_user); -accountRouter.put("/verify-otp", RequestValidator(account_validation.verify_otp), account_controller.verify_account_using_otp); -accountRouter.put("/verify-link", RequestValidator(account_validation.verify_link), account_controller.verify_account_using_link); -accountRouter.get("/me", auth("USER", "ADMIN"), account_controller.get_user_account); -accountRouter.put("/change-password", auth("USER", "ADMIN"), RequestValidator(account_validation.change_password), account_controller.change_password); -accountRouter.put("/resend-otp", RequestValidator(account_validation.resend_otp), account_controller.resend_otp_and_verification_link); -accountRouter.put("/forget-password", RequestValidator(account_validation.resend_otp), account_controller.forget_password_generate_reset_token); -accountRouter.put("/reset-password", RequestValidator(account_validation.reset_pass), account_controller.reset_password_using_token); -export default accountRouter; diff --git a/dist/app/modules/account/account.service.js b/dist/app/modules/account/account.service.js deleted file mode 100644 index 0b7b163..0000000 --- a/dist/app/modules/account/account.service.js +++ /dev/null @@ -1,371 +0,0 @@ -import bcrypt from "bcrypt"; -import { configs } from "../../configs/index.js"; -import { prisma } from "../../lib/prisma.js"; -import { emailQueue } from "../../queues/email/email.queue.js"; -import { AppError } from "../../utils/app_error.js"; -import { jwtHelpers } from "../../utils/JWT.js"; -import sendMail from "../../utils/mail_sender.js"; -import { otpGenerator } from "../../utils/otpGenerator.js"; -const create_account_into_db = async (req) => { - const payload = req?.body; - // check account exist or not - const existingAccount = await prisma.account.findUnique({ - where: { email: payload.email }, - }); - if (existingAccount) { - throw new AppError("Email already exists", 403); - } - // hash password - const hashPassword = bcrypt.hashSync(payload.password, 10); - // create account and profile - const result = await prisma.$transaction(async (tx) => { - const account = await tx.account.create({ - data: { - email: payload.email, - password: hashPassword, - }, - }); - const profile = await tx.profile.create({ - data: { - shopName: payload.shopName, - accountId: account.id, - }, - }); - return { - account, - profile, - }; - }); - // sending otp and verification link - const newOtp = otpGenerator(); - const verificationToken = jwtHelpers.generateToken({ - email: payload.email, - accountId: result.account.id, - }, configs.jwt.verified_token, "5m"); - const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`; - // save otp into db - await prisma.account.update({ - where: { - email: payload.email, - }, - data: { - lastOtp: newOtp, - lastOtpSendingTime: new Date(), - }, - }); - await emailQueue.add("email-queue", { - name: payload.shopName, - otp: newOtp, - verificationLink: verificationLink, - subject: "Welcome to Quick Launch - Verification OTP", - email: payload.email, - textBody: "You can use otp or verification link for verifying your account" - }, { - attempts: 1, - removeOnComplete: true, - removeOnFail: true, - }); - return null; -}; -const verify_account_using_otp_into_db = async (req) => { - const payload = req?.body; - // check account - const account = await prisma.account.findUnique({ - where: { - email: payload.email, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // match with last otp - const isOtpMatch = payload.otp === account.lastOtp; - if (!isOtpMatch) { - throw new AppError("Invalid OTP, Please try again!!", 401); - } - // check otp timing - const OTP_EXPIRY_TIME = 5 * 60 * 1000; // 5 minutes in ms - const isOtpExpired = account.lastOtpSendingTime - ? new Date().getTime() - new Date(account.lastOtpSendingTime).getTime() > - OTP_EXPIRY_TIME - : true; - if (isOtpExpired) { - throw new AppError("OTP Expired, Please try again!!", 401); - } - // change account status - await prisma.account.update({ - where: { - id: account.id, - }, - data: { - isAccountVerified: true, - }, - }); - // infuter user welcome email - return ""; -}; -const verify_account_using_link_into_db = async (req) => { - const token = req?.body?.token; - let decoadeToken; - try { - decoadeToken = jwtHelpers.verifyToken(token, configs.jwt.verified_token); - } - catch (error) { - if (error?.message == "invalid signature") { - throw new AppError("Invalid Token", 403); - } - else if (error?.message == "jwt expired") { - throw new AppError("Token expired, please reset again", 403); - } - } - // check account - const account = await prisma.account.findUnique({ - where: { - email: decoadeToken.email, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // change account status - await prisma.account.update({ - where: { - id: account.id, - }, - data: { - isAccountVerified: true, - }, - }); - // infuter user welcome email - return ""; -}; -const login_user_into_db = async (req) => { - const payload = req?.body; - const account = await prisma.account.findUnique({ - where: { - email: payload.email, - }, - select: { - id: true, - email: true, - role: true, - isAccountVerified: true, - isDeleted: true, - password: true, - profile: true, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // checking password - const isPasswordMatch = bcrypt.compareSync(payload.password, account.password); - if (!isPasswordMatch) { - throw new AppError("Invalid password", 401); - } - // check if account is deleted - if (account.isDeleted) { - throw new AppError("Account is deleted", 401); - } - // check if account is verified - if (!account.isAccountVerified) { - throw new AppError("Account is not verified", 401); - } - // generate access - const accessToken = jwtHelpers.generateToken({ - email: account.email, - role: account.role, - accountId: account.id, - }, configs.jwt.access_token, configs.jwt.access_expires); - const finalOutputData = { - id: account.id, - email: account.email, - role: account.role, - shopName: account?.profile?.shopName, - shopLogo: account?.profile?.shopLogo, - }; - return { - accessToken, - profile: finalOutputData - }; -}; -const get_user_account_from_db = async (req) => { - const user = req?.user; - const result = await prisma.account.findUnique({ - where: { - id: user?.accountId, - }, - select: { - id: true, - email: true, - role: true, - isAccountVerified: true, - isDeleted: true, - profile: true, - }, - }); - return result; -}; -const change_password_into_db = async (req) => { - const user = req?.user; - // payload - const payload = req?.body; - // check old and new password is not same - const isSamePassword = payload.oldPassword === payload.newPassword; - if (isSamePassword) { - throw new AppError("Old and new password are same, Please provide deffirent password", 404); - } - // check user validity - const isUserExist = await prisma.account.findFirst({ - where: { - email: user?.email, - }, - }); - // if account not exists - if (!isUserExist) { - throw new AppError("Account not found!!", 404); - } - // check old password - const isPasswordMatch = bcrypt.compareSync(payload.oldPassword, isUserExist.password); - if (!isPasswordMatch) { - throw new AppError("Incorrect password", 401); - } - // change password logic - const newHashPassword = bcrypt.hashSync(payload.newPassword, 10); - await prisma.account.update({ - where: { - id: isUserExist.id, - }, - data: { - password: newHashPassword, - }, - }); - // in future email notification for more sucurity - return ""; -}; -const resend_otp_and_verification_link_from_db = async (req) => { - const email = req?.body?.email; - const account = await prisma.account.findUnique({ - where: { - email, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // if already verified - if (account.isAccountVerified) { - throw new AppError("Account already verified", 403); - } - // make new otp and verification link - const newOtp = otpGenerator(); - const verificationToken = jwtHelpers.generateToken({ - email, - accountId: account.id, - }, configs.jwt.verified_token, "5m"); - const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`; - // save otp into db - await prisma.account.update({ - where: { - email, - }, - data: { - lastOtp: newOtp, - lastOtpSendingTime: new Date(), - }, - }); - await sendMail({ - to: email, - subject: "New Verification otp and link", - htmlBody: ` -

OTP ${newOtp}

- Otp will be expire in 5 minutes - -

- -

Or you can use Verification link

-

${verificationLink}

- `, - textBody: "You can use otp or direct link", - }); -}; -const forget_password_generate_reset_token_from_db = async (req) => { - const email = req?.body?.email; - const account = await prisma.account.findUnique({ - where: { - email, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // generate forget token - const verificationToken = jwtHelpers.generateToken({ - email: email, - accountId: account.id, - }, configs.jwt.verified_token, "5m"); - const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`; - await sendMail({ - to: email, - subject: "Forget Password- Use this link for new password ", - htmlBody: ` -

Your Reset Link:

-

${verificationLink}

- `, - textBody: "", - }); -}; -const reset_password_using_token_into_db = async (req) => { - const token = req?.body?.token; - const newPass = req?.body?.newPass; - let decoadeToken; - try { - decoadeToken = jwtHelpers.verifyToken(token, configs.jwt.verified_token); - } - catch (error) { - if (error?.message == "invalid signature") { - throw new AppError("Invalid Token", 403); - } - else if (error?.message == "jwt expired") { - throw new AppError("Link expired, please reset again", 403); - } - } - // check account - const account = await prisma.account.findUnique({ - where: { - email: decoadeToken.email, - }, - }); - // check if account exists - if (!account) { - throw new AppError("Account not found", 404); - } - // change account password - const newHash = bcrypt.hashSync(newPass, 10); - await prisma.account.update({ - where: { - id: account.id, - }, - data: { - password: newHash, - }, - }); - // infuter user alart for changing password - return ""; -}; -export const account_services = { - create_account_into_db, - login_user_into_db, - get_user_account_from_db, - change_password_into_db, - verify_account_using_otp_into_db, - resend_otp_and_verification_link_from_db, - verify_account_using_link_into_db, - forget_password_generate_reset_token_from_db, - reset_password_using_token_into_db -}; diff --git a/dist/app/modules/account/account.swagger.js b/dist/app/modules/account/account.swagger.js deleted file mode 100644 index c756f62..0000000 --- a/dist/app/modules/account/account.swagger.js +++ /dev/null @@ -1,187 +0,0 @@ -export const accountSwaggerDocs = { - "/api/auth/sign-up": { - post: { - tags: ["account"], - summary: "Create new account", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - email: "user@gmail.com", - password: "password", - shopName: "User", - }), - }, - }, - }, - responses: { - 201: { description: "account created successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/sign-in": { - post: { - tags: ["account"], - summary: "Sign In your account", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - email: "user@gmail.com", - password: "password", - }), - }, - }, - }, - responses: { - 201: { description: "User signed in successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/verify-otp": { - put: { - tags: ["account"], - summary: "Verify OTP", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - email: "user@gmail.com", - otp: "654321", - }), - }, - }, - }, - responses: { - 201: { description: "OTP verification successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/verify-link": { - put: { - tags: ["account"], - summary: "Verify Link", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - token: "dsakfjasdkj", - }), - }, - }, - }, - responses: { - 201: { description: "Token verification successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/me": { - get: { - tags: ["account"], - summary: "Get me account", - description: "", - responses: { - 200: { description: "account fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, - "/api/auth/change-password": { - put: { - tags: ["account"], - summary: "Change Password", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - oldPassword: "123456", - newPassword: "654321", - }), - }, - }, - }, - responses: { - 201: { description: "Passwrod change successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/resend-otp": { - put: { - tags: ["account"], - summary: "Resend OTP", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - email: "user@gmail.com", - }), - }, - }, - }, - responses: { - 201: { description: "OTP resend successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/forget-password": { - put: { - tags: ["account"], - summary: "Forget Password", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - email: "user@gmail.com", - }), - }, - }, - }, - responses: { - 201: { description: "Forget password successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, - "/api/auth/reset-password": { - put: { - tags: ["account"], - summary: "Reset Password", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - token: "dkfjadskfds", - newPass: "newpass", - }), - }, - }, - }, - responses: { - 201: { description: "Password reset successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, -}; diff --git a/dist/app/modules/account/account.validation.js b/dist/app/modules/account/account.validation.js deleted file mode 100644 index c761159..0000000 --- a/dist/app/modules/account/account.validation.js +++ /dev/null @@ -1,37 +0,0 @@ -import z from "zod"; -const sign_up = z.object({ - email: z.string("Email is required."), - password: z.string("Password is required."), - shopName: z.string("Full name is required."), -}); -const sing_in = z.object({ - email: z.string("Email is required."), - password: z.string("Password is required."), -}); -const change_password = z.object({ - oldPassword: z.string("Old Password is required"), - newPassword: z.string("New Password is required"), -}); -const verify_otp = z.object({ - email: z.string("Email is required"), - otp: z.string("OTP is required"), -}); -const verify_link = z.object({ - token: z.string("Token is required "), -}); -const resend_otp = z.object({ - email: z.string("Email is required"), -}); -const reset_pass = z.object({ - token: z.string("Token is required"), - newPass: z.string("Password is required"), -}); -export const account_validation = { - sign_up, - sing_in, - change_password, - verify_otp, - resend_otp, - verify_link, - reset_pass -}; diff --git a/dist/app/modules/order/order.controller.js b/dist/app/modules/order/order.controller.js deleted file mode 100644 index d35964e..0000000 --- a/dist/app/modules/order/order.controller.js +++ /dev/null @@ -1,60 +0,0 @@ -import catchAsync from "../../utils/catch_async.js"; -import manageResponse from "../../utils/manage_response.js"; -import { order_service } from "./order.service.js"; -const get_all_order = catchAsync(async (req, res) => { - const result = await order_service.get_all_order_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "All order fetched successfully.", - data: result, - meta: {}, - }); -}); -const get_single_order = catchAsync(async (req, res) => { - const result = await order_service.get_single_order_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "Single order fetched successfully.", - data: result, - meta: {}, - }); -}); -const create_order = catchAsync(async (req, res) => { - const result = await order_service.create_order_into_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "order created successfully.", - data: result, - meta: {}, - }); -}); -const update_order = catchAsync(async (req, res) => { - const result = await order_service.update_order_into_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "order updated successfully.", - data: result, - meta: {}, - }); -}); -const delete_order = catchAsync(async (req, res) => { - const result = await order_service.delete_order_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "order deleted successfully.", - data: result, - meta: {}, - }); -}); -export const order_controller = { - get_all_order, - get_single_order, - create_order, - update_order, - delete_order, -}; diff --git a/dist/app/modules/order/order.route.js b/dist/app/modules/order/order.route.js deleted file mode 100644 index 6950849..0000000 --- a/dist/app/modules/order/order.route.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Router } from "express"; -import RequestValidator from "../../middlewares/request_validator.js"; -import { order_controller } from "./order.controller.js"; -import { order_validations } from "./order.validation.js"; -import auth from "../../middlewares/auth.js"; -const router = Router(); -router.get("/", order_controller.get_all_order); -router.post("/", RequestValidator(order_validations.create_order), order_controller.create_order); -router.get("/:id", order_controller.get_single_order); -router.patch("/:id", auth("ADMIN"), RequestValidator(order_validations.update_order), order_controller.update_order); -router.delete("/:id", order_controller.delete_order); -export default router; diff --git a/dist/app/modules/order/order.service.js b/dist/app/modules/order/order.service.js deleted file mode 100644 index c33490e..0000000 --- a/dist/app/modules/order/order.service.js +++ /dev/null @@ -1,163 +0,0 @@ -import { configs } from "../../configs/index.js"; -import { prisma } from "../../lib/prisma.js"; -import { orderEmailQueue } from "../../queues/email/order/order.email.queue.js"; -import { AppError } from "../../utils/app_error.js"; -import paginationHelper from "../../utils/pagination_helper.js"; -const get_all_order_from_db = async (req) => { - // define your own login here - const search = req.query.search; - const customerName = req.query.customerName; - const productName = req.query.productName; - // for date filter - const startDate = req.query.startDate; - const endDate = req.query.endDate; - const status = req.query.status || undefined; - const { page, limit, skip, sortBy, sortOrder } = paginationHelper(req.query); - const andCondition = []; - if (search) { - andCondition.push({ - OR: [ - { - productName: { - contains: search, - mode: "insensitive", - }, - }, - ], - }); - } - if (customerName) { - andCondition.push({ - OR: [ - { - customerName: { - contains: customerName, - mode: "insensitive", - }, - }, - ], - }); - } - if (productName) { - andCondition.push({ - OR: [ - { - productName: { - contains: productName, - mode: "insensitive", - }, - }, - ], - }); - } - if (status) { - andCondition.push({ - OR: [ - { - status: { - contains: status, - mode: "insensitive", - }, - }, - ], - }); - } - // for date filter - const dateFilter = {}; - if (startDate) { - const start = new Date(startDate); - start.setHours(0, 0, 0, 0); - dateFilter.gte = start; - } - if (endDate) { - const end = new Date(endDate); - end.setHours(23, 59, 59, 999); - dateFilter.lte = end; - } - if (Object.keys(dateFilter).length > 0) { - andCondition.push({ - createdAt: dateFilter, - }); - } - const getAllOrders = await prisma.order.findMany({ - take: limit, - skip, - where: { - AND: andCondition, - }, - orderBy: { - [sortBy]: sortOrder, - }, - }); - const result = await prisma.order.count({ - where: { - AND: andCondition, - }, - }); - return { - data: getAllOrders, - pagination: { - total: result, - page, - limit, - totalPages: Math.ceil(result / limit), - }, - }; -}; -const get_single_order_from_db = async (req) => { - // define your own login here - const { id } = req.params; - const result = await prisma.order.findUnique({ where: { id } }); - return result; -}; -const create_order_into_db = async (req) => { - const payload = req?.body; - console.log(payload); - payload.status = "INITIATED"; - payload.paymentType = "COD"; - // nwo init order - const result = await prisma.order.create({ data: payload }); - // if email exist sent tracking link - if (payload.customerEmail) { - const trackingLink = `${configs.jwt.front_end_url}/track-order/${result.id}`; - await orderEmailQueue.add("order-email-queue", { - email: payload.customerEmail, - subject: "Order Tracking", - textBody: `Your order has been created. Track your order here: ${trackingLink}`, - htmlBody: `

Your order has been created. Track your order here: Track Order

`, - }); - } - return result; -}; -const update_order_into_db = async (req) => { - // define your own login here - const user = req.user; - console.log(user); - if (user?.role !== "ADMIN") { - throw new AppError("You are not authorized to perform this action", 403); - } - const { id } = req.params; - const isProductExist = await prisma.order.findUnique({ where: { id } }); - if (!isProductExist) { - throw new AppError("Order is not found", 404); - } - const result = await prisma.order.update({ where: { id }, data: req.body }); - return result; -}; -const delete_order_from_db = async (req) => { - // define your own login here - const { id } = req.params; - const user = req.user; - if (user?.role !== "ADMIN") { - throw new AppError("You are not authorized to perform this action", 403); - } - const result = await prisma.order.delete({ where: { id } }); - return result; -}; -export const order_service = { - get_all_order_from_db, - get_single_order_from_db, - create_order_into_db, - update_order_into_db, - delete_order_from_db, -}; diff --git a/dist/app/modules/order/order.swagger.js b/dist/app/modules/order/order.swagger.js deleted file mode 100644 index d3b880d..0000000 --- a/dist/app/modules/order/order.swagger.js +++ /dev/null @@ -1,165 +0,0 @@ -export const orderSwaggerDocs = { - "/api/order": { - post: { - tags: ["order"], - summary: "Create new order", - description: ` INITIATED - CONFIRMED - ONGOING - DELIVERED - CANCELLED`, - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - shopAccountId: "", - productPrice: 1500, - productQuantity: 2, - productName: "Wireless Mouse", - customerName: "Rahim Uddin", - customerPhone: "+8801712345678", - customerEmail: "softvence.abumahid@gmail.com", - customerAddress: "Rangpur, Bangladesh", - customerNote: "Please deliver between 3-5 PM", - }), - }, - }, - }, - responses: { - 201: { description: "order created successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - get: { - tags: ["order"], - summary: "Get all order", - description: "", - parameters: [ - { - name: "page", - in: "query", - required: false, - schema: { type: "number" }, - }, - { - name: "limit", - in: "query", - required: false, - schema: { type: "number" }, - }, - { - name: "search", - in: "query", - required: false, - schema: { type: "string" }, - }, - { - name: "customerName", - in: "query", - required: false, - schema: { type: "string" }, - }, - { - name: "productName", - in: "query", - required: false, - schema: { type: "string" }, - }, - { - name: "status", - in: "query", - required: false, - schema: { type: "string" }, - }, - { - name: "date", - in: "query", - required: false, - schema: { type: "string" }, - }, - { - name: "startDate", - in: "query", - required: false, - schema: { type: "string", format: "date" }, - example: "2026-04-01", - }, - { - name: "endDate", - in: "query", - required: false, - schema: { type: "string", format: "date" }, - example: "2026-04-31", - }, - ], - responses: { - 200: { description: "order fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, - "/api/order/{id}": { - get: { - tags: ["order"], - summary: "Get single order", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "order fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - patch: { - tags: ["order"], - summary: "Update order -(Admin route)", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - status: "INITIATED", - }), // put your request body - }, - }, - }, - responses: { - 200: { description: "order updated successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - delete: { - tags: ["order"], - summary: "Delete order", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "order delete successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, -}; diff --git a/dist/app/modules/order/order.validation.js b/dist/app/modules/order/order.validation.js deleted file mode 100644 index 0debae2..0000000 --- a/dist/app/modules/order/order.validation.js +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from "zod"; -const create_order = z.object({ - shopAccountId: z.string(), - productPrice: z.number(), - productQuantity: z.number(), - productName: z.string(), - customerName: z.string(), - customerPhone: z.string(), - customerEmail: z.string().optional(), - customerAddress: z.string(), - customerNote: z.string().optional() -}); -const update_order = z.object({ - status: z.string().optional() -}); -export const order_validations = { - create_order, - update_order, -}; diff --git a/dist/app/modules/plan/plan.controller.js b/dist/app/modules/plan/plan.controller.js deleted file mode 100644 index b03bf85..0000000 --- a/dist/app/modules/plan/plan.controller.js +++ /dev/null @@ -1,60 +0,0 @@ -import catchAsync from "../../utils/catch_async.js"; -import manageResponse from "../../utils/manage_response.js"; -import { plan_service } from "./plan.service.js"; -const get_all_plan = catchAsync(async (req, res) => { - const result = await plan_service.get_all_plan_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "All plan fetched successfully.", - data: result, - meta: {}, - }); -}); -const get_single_plan = catchAsync(async (req, res) => { - const result = await plan_service.get_single_plan_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "Single plan fetched successfully.", - data: result, - meta: {}, - }); -}); -const create_plan = catchAsync(async (req, res) => { - const result = await plan_service.create_plan_into_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "plan created successfully.", - data: result, - meta: {}, - }); -}); -const update_plan = catchAsync(async (req, res) => { - const result = await plan_service.update_plan_into_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "plan updated successfully.", - data: result, - meta: {}, - }); -}); -const delete_plan = catchAsync(async (req, res) => { - const result = await plan_service.delete_plan_from_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "plan deleted successfully.", - data: result, - meta: {}, - }); -}); -export const plan_controller = { - get_all_plan, - get_single_plan, - create_plan, - update_plan, - delete_plan, -}; diff --git a/dist/app/modules/plan/plan.route.js b/dist/app/modules/plan/plan.route.js deleted file mode 100644 index 5656a72..0000000 --- a/dist/app/modules/plan/plan.route.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Router } from "express"; -import auth from "../../middlewares/auth.js"; -import RequestValidator from "../../middlewares/request_validator.js"; -import { plan_controller } from "./plan.controller.js"; -import { plan_validations } from "./plan.validation.js"; -const router = Router(); -router.get("/", plan_controller.get_all_plan); -router.post("/", RequestValidator(plan_validations.create_plan), auth("ADMIN"), plan_controller.create_plan); -router.get("/:id", plan_controller.get_single_plan); -router.patch("/:id", RequestValidator(plan_validations.update_plan), auth("ADMIN"), plan_controller.update_plan); -router.delete("/:id", auth("ADMIN"), plan_controller.delete_plan); -export default router; diff --git a/dist/app/modules/plan/plan.service.js b/dist/app/modules/plan/plan.service.js deleted file mode 100644 index 56dc58e..0000000 --- a/dist/app/modules/plan/plan.service.js +++ /dev/null @@ -1,68 +0,0 @@ -import { prisma } from "../../lib/prisma.js"; -import { AppError } from "../../utils/app_error.js"; -const get_all_plan_from_db = async (req) => { - // define your own login here - const result = await prisma.plan.findMany(); - return result; -}; -const get_single_plan_from_db = async (req) => { - // define your own login here - const { id } = req.params; - const result = await prisma.plan.findUnique({ - where: { - id: id - } - }); - return result; -}; -const create_plan_into_db = async (req) => { - // define your own login here - const user = req?.user; - if (user?.role !== "ADMIN") { - throw new AppError("You don’t have permission to create plan information.!!!", 401); - } - const result = await prisma.plan.create({ data: req.body }); - return result; -}; -const update_plan_into_db = async (req) => { - // define your own login here - const { id } = req.params; - const user = req.user; - if (user?.role !== "ADMIN") { - throw new AppError("You don’t have permission to update plan information.!!!", 401); - } - const isPlanExist = await prisma.plan.findFirst({ - where: { - id: id - } - }); - if (!isPlanExist) { - throw new AppError("The plan is not available!!!", 404); - } - const result = await prisma.plan.update({ - where: { - id: isPlanExist.id - }, - data: { - ...req.body - } - }); - return result; -}; -const delete_plan_from_db = async (req) => { - // define your own login here - const { id } = req.params; - const user = req.user; - if (user?.role !== "ADMIN") { - throw new AppError("You don’t have permission to delete plan information.!!!", 401); - } - const result = await prisma.plan.delete({ where: { id: id } }); - return result; -}; -export const plan_service = { - get_all_plan_from_db, - get_single_plan_from_db, - create_plan_into_db, - update_plan_into_db, - delete_plan_from_db, -}; diff --git a/dist/app/modules/plan/plan.swagger.js b/dist/app/modules/plan/plan.swagger.js deleted file mode 100644 index eb85a64..0000000 --- a/dist/app/modules/plan/plan.swagger.js +++ /dev/null @@ -1,125 +0,0 @@ -export const planSwaggerDocs = { - "/api/plan": { - post: { - tags: ["plan"], - summary: "Create new plan", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - "planName": "PRO Plan", - "price": 12, - "planType": "PRO", - "planDesc": "The plan is only for pro users", - "planFeatures": { - "storage": "10GB", - "projects": 5, - "support": "Email Support" - } - }), // put your request body - }, - }, - }, - responses: { - 201: { description: "plan created successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - get: { - tags: ["plan"], - summary: "Get all plan", - description: "", - parameters: [ - { - name: "page", - in: "query", - required: false, - schema: { type: "number" }, - }, - { - name: "limit", - in: "query", - required: false, - schema: { type: "number" }, - }, - ], - responses: { - 200: { description: "plan fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, - "/api/plan/{id}": { - get: { - tags: ["plan"], - summary: "Get single plan", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "plan fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - patch: { - tags: ["plan"], - summary: "Update plan", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - "planName": "PRO Plan", - "price": 12, - "planType": "PRO", - "planDesc": "The plan is only for pro users", - "planFeatures": { - "storage": "10GB", - "projects": 5, - "support": "Email Support" - } - }), // put your request body - }, - }, - }, - responses: { - 200: { description: "plan updated successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - delete: { - tags: ["plan"], - summary: "Delete plan", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "plan delete successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, -}; diff --git a/dist/app/modules/plan/plan.validation.js b/dist/app/modules/plan/plan.validation.js deleted file mode 100644 index d38d612..0000000 --- a/dist/app/modules/plan/plan.validation.js +++ /dev/null @@ -1,33 +0,0 @@ -import { z } from "zod"; -const create_plan = z.object({ - planName: z.string("Enter the plan name..."), - price: z.number("Enter the plan price..."), - planType: z.enum(["FREE", "STANDARD", "PRO"]), - planDesc: z.string("Enter the plan description..."), - planFeatures: z.union([ - z.string(), - z.number(), - z.boolean(), - z.null(), - z.array(z.any()), - z.record(z.string(), z.any()) - ]) -}); -const update_plan = z.object({ - planName: z.string(), - price: z.number(), - planType: z.enum(["FREE", "STANDARD", "PRO"]), - planDesc: z.string().optional(), - planFeatures: z.union([ - z.string(), - z.number(), - z.boolean(), - z.null(), - z.array(z.any()), - z.record(z.string(), z.any()) - ]) -}); -export const plan_validations = { - create_plan, - update_plan, -}; diff --git a/dist/app/modules/profile/profile.controller.js b/dist/app/modules/profile/profile.controller.js deleted file mode 100644 index e6abe89..0000000 --- a/dist/app/modules/profile/profile.controller.js +++ /dev/null @@ -1,15 +0,0 @@ -import catchAsync from "../../utils/catch_async.js"; -import manageResponse from "../../utils/manage_response.js"; -import { profile_service } from "./profile.service.js"; -const update_profile = catchAsync(async (req, res) => { - const result = await profile_service.update_profile_into_db(req); - manageResponse(res, { - success: true, - statusCode: 200, - message: "profile updated successfully.", - data: result, - }); -}); -export const profile_controller = { - update_profile, -}; diff --git a/dist/app/modules/profile/profile.route.js b/dist/app/modules/profile/profile.route.js deleted file mode 100644 index 5a408a2..0000000 --- a/dist/app/modules/profile/profile.route.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Router } from "express"; -import RequestValidator from "../../middlewares/request_validator.js"; -import { profile_controller } from "./profile.controller.js"; -import { profile_validations } from "./profile.validation.js"; -import auth from "../../middlewares/auth.js"; -import uploader from "../../middlewares/uploader.js"; -const router = Router(); -router.patch("/", auth("USER"), uploader.single("file"), (req, res, next) => { - req.body = JSON.parse(req?.body?.data); - next(); -}, RequestValidator(profile_validations.update_profile), profile_controller.update_profile); -export default router; diff --git a/dist/app/modules/profile/profile.service.js b/dist/app/modules/profile/profile.service.js deleted file mode 100644 index 2ed624d..0000000 --- a/dist/app/modules/profile/profile.service.js +++ /dev/null @@ -1,23 +0,0 @@ -import uploadCloud from "../../utils/cloudinary.js"; -import { prisma } from "../../lib/prisma.js"; -const update_profile_into_db = async (req) => { - const user = req?.user; - const payload = req?.body; - const file = req?.file; - console.log(payload); - // check file and upload to cloud - if (file) { - const cloudRes = await uploadCloud(file); - payload.profilePhoto = cloudRes?.secure_url; - } - const result = await prisma.profile.update({ - where: { - accountId: user.accountId, - }, - data: payload, - }); - return result; -}; -export const profile_service = { - update_profile_into_db, -}; diff --git a/dist/app/modules/profile/profile.swagger.js b/dist/app/modules/profile/profile.swagger.js deleted file mode 100644 index bdfe3c2..0000000 --- a/dist/app/modules/profile/profile.swagger.js +++ /dev/null @@ -1,34 +0,0 @@ -export const profileSwaggerDocs = { - "/api/profile": { - patch: { - tags: ["profile"], - summary: "Update profile", - requestBody: { - required: true, - content: { - "multipart/form-data": { - schema: { - type: "object", - properties: { - data: { - type: "object", - properties: { - fullName: { type: "string" }, - }, - }, - file: { - type: "string", - format: "binary", - }, - }, - }, - }, - }, - }, - responses: { - 200: { description: "profile updated successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - }, -}; diff --git a/dist/app/modules/profile/profile.validation.js b/dist/app/modules/profile/profile.validation.js deleted file mode 100644 index bb0240a..0000000 --- a/dist/app/modules/profile/profile.validation.js +++ /dev/null @@ -1,7 +0,0 @@ -import { z } from "zod"; -const update_profile = z.object({ - fullName: z.string().optional(), -}); -export const profile_validations = { - update_profile, -}; diff --git a/dist/app/modules/support/support.controller.js b/dist/app/modules/support/support.controller.js deleted file mode 100644 index deedd95..0000000 --- a/dist/app/modules/support/support.controller.js +++ /dev/null @@ -1,80 +0,0 @@ -import catchAsync from "../../utils/catch_async.js"; -import manageResponse from "../../utils/manage_response.js"; -import { support_service } from "./support.service.js"; -const createSupport = catchAsync(async (req, res) => { - const id = req?.user?.accountId; - const data = { - ...req.body, - storeAccountId: id - }; - const result = await support_service.createSupportIntoDB(data); - manageResponse(res, { - success: true, - statusCode: 200, - message: "support created successfully.", - data: result, - meta: {}, - }); -}); -const getAllSupport = catchAsync(async (req, res) => { - const role = req?.user?.role; - const id = req?.user?.accountId; - const search = req?.query?.search; - const type = req?.query?.type; - const status = req?.query?.status; - const result = await support_service.getAllSupportFromDB(id, role, search, type, status); - manageResponse(res, { - success: true, - statusCode: 200, - message: "All support fetched successfully.", - data: result, - meta: {}, - }); -}); -const get_single_support = catchAsync(async (req, res) => { - const { id } = req.params; - const userId = req?.user?.accountId; - const role = req?.user?.role; - const result = await support_service.getSingleSupportFromDB(id, userId, role); - manageResponse(res, { - success: true, - statusCode: 200, - message: "Single support fetched successfully.", - data: result, - meta: {}, - }); -}); -const update_support = catchAsync(async (req, res) => { - const { id } = req.params; - const userId = req?.user?.accountId; - const role = req?.user?.role; - const data = req.body; - const result = await support_service.updateSupportIntoDB(id, userId, role, data); - manageResponse(res, { - success: true, - statusCode: 200, - message: "support updated successfully.", - data: result, - meta: {}, - }); -}); -const delete_support = catchAsync(async (req, res) => { - const { id } = req.params; - const userId = req?.user?.accountId; - const role = req?.user?.role; - const result = await support_service.deleteSupportFromDB(id, userId, role); - manageResponse(res, { - success: true, - statusCode: 200, - message: "support deleted successfully.", - data: result, - meta: {}, - }); -}); -export const support_controller = { - createSupport, - getAllSupport, - get_single_support, - update_support, - delete_support, -}; diff --git a/dist/app/modules/support/support.route.js b/dist/app/modules/support/support.route.js deleted file mode 100644 index 6babe9b..0000000 --- a/dist/app/modules/support/support.route.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Router } from "express"; -import RequestValidator from "../../middlewares/request_validator.js"; -import { support_controller } from "./support.controller.js"; -import { support_validations } from "./support.validation.js"; -import auth from "../../middlewares/auth.js"; -const router = Router(); -router.get("/", auth("ADMIN", "USER"), support_controller.getAllSupport); -router.post("/", auth("ADMIN", "USER"), RequestValidator(support_validations.create_support), support_controller.createSupport); -router.get("/:id", auth("ADMIN", "USER"), support_controller.get_single_support); -router.patch("/:id", auth("ADMIN", "USER"), RequestValidator(support_validations.update_support), support_controller.update_support); -router.delete("/:id", auth("ADMIN", "USER"), support_controller.delete_support); -export default router; diff --git a/dist/app/modules/support/support.service.js b/dist/app/modules/support/support.service.js deleted file mode 100644 index 0825aaa..0000000 --- a/dist/app/modules/support/support.service.js +++ /dev/null @@ -1,100 +0,0 @@ -import { prisma } from "../../lib/prisma.js"; -import { AppError } from "../../utils/app_error.js"; -const createSupportIntoDB = async (payload) => { - const result = await prisma.support.create({ data: payload }); - return result; -}; -const getAllSupportFromDB = async (user_id, role, search, type, status) => { - const andCondition = []; - if (search) { - andCondition.push({ - OR: [ - { - issueName: { - contains: search, - mode: "insensitive", - }, - }, - { - description: { - contains: search, - mode: "insensitive", - }, - }, - ], - }); - } - if (type) { - andCondition.push({ - type: type, - }); - } - if (status) { - andCondition.push({ - status: status, - }); - } - if (role !== "ADMIN") { - andCondition.push({ - storeAccountId: user_id, - }); - } - const whereCondition = andCondition.length > 0 ? { AND: andCondition } : {}; - const result = await prisma.support.findMany({ - where: whereCondition, - orderBy: { - createdAt: "desc", - }, - }); - return result; -}; -const getSingleSupportFromDB = async (id, userId, role) => { - const support = await prisma.support.findUnique({ - where: { id }, - }); - if (!support) { - throw new AppError("Support not found", 404); - } - if (role !== "ADMIN" && support.storeAccountId !== userId) { - throw new AppError("You are not authorized", 403); - } - return support; -}; -const updateSupportIntoDB = async (id, userId, role, payload) => { - const support = await prisma.support.findUnique({ - where: { id }, - }); - if (!support) { - throw new AppError("Support not found", 404); - } - if (role !== "ADMIN" && support.storeAccountId !== userId) { - throw new AppError("You are not authorized", 403); - } - const result = await prisma.support.update({ - where: { id }, - data: payload, - }); - return result; -}; -const deleteSupportFromDB = async (id, userId, role) => { - const support = await prisma.support.findUnique({ - where: { id }, - }); - if (!support) { - throw new AppError("Support not found", 404); - } - if (role !== "ADMIN" && support.storeAccountId !== userId) { - throw new AppError("You are not authorized", 403); - } - const result = await prisma.support.delete({ - where: { id } - }); - return result; -}; -export const support_service = { - createSupportIntoDB, - getAllSupportFromDB, - getSingleSupportFromDB, - updateSupportIntoDB, - deleteSupportFromDB, -}; diff --git a/dist/app/modules/support/support.swagger.js b/dist/app/modules/support/support.swagger.js deleted file mode 100644 index cd29843..0000000 --- a/dist/app/modules/support/support.swagger.js +++ /dev/null @@ -1,109 +0,0 @@ -export const supportSwaggerDocs = { - "/api/support": { - post: { - tags: ["support"], - summary: "Create new support", - description: "", - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({ - "issueName": "Your issue name", - "description": "Issue description", - "type": "Issue Type" - }), // put your request body - }, - }, - }, - responses: { - 201: { description: "support created successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - get: { - tags: ["support"], - summary: "Get all support", - description: "", - parameters: [ - { - name: "page", - in: "query", - required: false, - schema: { type: "number" }, - }, - { - name: "limit", - in: "query", - required: false, - schema: { type: "number" }, - }, - ], - responses: { - 200: { description: "support fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, - "/api/support/{id}": { - get: { - tags: ["support"], - summary: "Get single support", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "support fetched successfully" }, - 401: { description: "unauthorized" }, - }, - }, - patch: { - tags: ["support"], - summary: "Update support", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - requestBody: { - required: true, - content: { - "application/json": { - example: JSON.stringify({}), // put your request body - }, - }, - }, - responses: { - 200: { description: "support updated successfully" }, - 500: { description: "Validation error or internal server error" }, - }, - }, - delete: { - tags: ["support"], - summary: "Delete support", - description: "", - parameters: [ - { - name: "id", - in: "path", - required: true, - schema: { type: "string" }, - }, - ], - responses: { - 200: { description: "support delete successfully" }, - 401: { description: "unauthorized" }, - }, - }, - }, -}; diff --git a/dist/app/modules/support/support.validation.js b/dist/app/modules/support/support.validation.js deleted file mode 100644 index 4ccbd97..0000000 --- a/dist/app/modules/support/support.validation.js +++ /dev/null @@ -1,28 +0,0 @@ -import { z } from "zod"; -const create_support = z.object({ - issueName: z.string().min(1, "issueName is required"), - description: z.string().min(1, "description is required"), - type: z.enum([ - "TECHNICAL", - "BILLING", - "DOMAIN", - "TEMPLATE", - "PAYMENT", - "ACCOUNT", - "FEATURE_REQUEST", - "BUG", - "OTHER", - ]), -}); -const update_support = z.object({ - issueName: z.string().optional(), - description: z.string().optional(), - type: z.enum(["BUG", "PAYMENT", "ACCOUNT", "OTHER"]).optional(), - status: z.enum(["OPEN", "IN_PROGRESS", "RESOLVED", "REJECTED"]).optional(), - resolvedBy: z.string().optional(), - resolvedAt: z.coerce.date().optional(), -}); -export const support_validations = { - create_support, - update_support, -}; diff --git a/dist/app/queues/connection.js b/dist/app/queues/connection.js deleted file mode 100644 index 32ed72d..0000000 --- a/dist/app/queues/connection.js +++ /dev/null @@ -1,7 +0,0 @@ -import { Redis } from "ioredis"; -import { configs } from "../configs/index.js"; -export const redisConnection = new Redis(configs.redis_url, { - tls: {}, - maxRetriesPerRequest: null, - enableReadyCheck: false, -}); diff --git a/dist/app/queues/email/email.processor.js b/dist/app/queues/email/email.processor.js deleted file mode 100644 index e7ddd44..0000000 --- a/dist/app/queues/email/email.processor.js +++ /dev/null @@ -1,14 +0,0 @@ -import { otpTemplate } from "../../templates/otpTemplate.js"; -import sendMail from "../../utils/mail_sender.js"; -// email.processor.ts -export const emailProcessor = async (job) => { - const payload = job.data; - await sendMail({ - to: payload.email, - subject: payload.subject, - htmlBody: otpTemplate(payload), - textBody: payload.textBody || "", - name: payload.name, - }); - console.log("Sending email job complete:", job.id); -}; diff --git a/dist/app/queues/email/email.queue.js b/dist/app/queues/email/email.queue.js deleted file mode 100644 index afb2b7c..0000000 --- a/dist/app/queues/email/email.queue.js +++ /dev/null @@ -1,6 +0,0 @@ -// email.queue.ts -import { Queue } from "bullmq"; -import { redisConnection } from "../connection.js"; -export const emailQueue = new Queue("email-queue", { - connection: redisConnection, -}); diff --git a/dist/app/queues/email/email.worker.js b/dist/app/queues/email/email.worker.js deleted file mode 100644 index 2130b4d..0000000 --- a/dist/app/queues/email/email.worker.js +++ /dev/null @@ -1,7 +0,0 @@ -// email.worker.ts -import { Worker } from "bullmq"; -import { redisConnection } from "../connection.js"; -import { emailProcessor } from "./email.processor.js"; -export const emailWorker = new Worker("email-queue", async (job) => emailProcessor(job), { - connection: redisConnection, -}); diff --git a/dist/app/queues/email/order/order.email.processor.js b/dist/app/queues/email/order/order.email.processor.js deleted file mode 100644 index 8b0834f..0000000 --- a/dist/app/queues/email/order/order.email.processor.js +++ /dev/null @@ -1,12 +0,0 @@ -import sendMail from "../../../utils/mail_sender.js"; -// email.processor.ts -export const orderEmailProcessor = async (job) => { - const payload = job.data; - await sendMail({ - to: payload.email, - subject: payload.subject, - htmlBody: payload.htmlBody, - textBody: payload.textBody, - }); - console.log("Sending email job complete:", job.id); -}; diff --git a/dist/app/queues/email/order/order.email.queue.js b/dist/app/queues/email/order/order.email.queue.js deleted file mode 100644 index 5e8bd36..0000000 --- a/dist/app/queues/email/order/order.email.queue.js +++ /dev/null @@ -1,5 +0,0 @@ -import { Queue } from "bullmq"; -import { redisConnection } from "../../connection.js"; -export const orderEmailQueue = new Queue("order-email-queue", { - connection: redisConnection, -}); diff --git a/dist/app/queues/email/order/order.email.worker.js b/dist/app/queues/email/order/order.email.worker.js deleted file mode 100644 index 4dbd0a1..0000000 --- a/dist/app/queues/email/order/order.email.worker.js +++ /dev/null @@ -1,7 +0,0 @@ -// email.worker.ts -import { Worker } from "bullmq"; -import { redisConnection } from "../../connection.js"; -import { orderEmailProcessor } from "./order.email.processor.js"; -export const emailWorker = new Worker("order-email-queue", async (job) => orderEmailProcessor(job), { - connection: redisConnection, -}); diff --git a/dist/app/queues/worker.js b/dist/app/queues/worker.js deleted file mode 100644 index 5801c24..0000000 --- a/dist/app/queues/worker.js +++ /dev/null @@ -1,3 +0,0 @@ -import "./email/email.worker.js"; -import "./email/order/order.email.worker.js"; -console.log("Workers running..."); diff --git a/dist/app/templates/otpTemplate.js b/dist/app/templates/otpTemplate.js deleted file mode 100644 index e6902d6..0000000 --- a/dist/app/templates/otpTemplate.js +++ /dev/null @@ -1,80 +0,0 @@ -export const otpTemplate = (payload) => { - return ` -
- - - - -
-

- Use the following One-Time Password (OTP) to complete your - verification: -

- - -
- - ${payload.otp} - -
- -

- This OTP will expire in 5 minutes. -

- - -
- - -

- Or verify using this link: -

- -

- - ${payload.verificationLink} - -

-
-
- `; -}; diff --git a/dist/app/utils/JWT.js b/dist/app/utils/JWT.js deleted file mode 100644 index 28765e5..0000000 --- a/dist/app/utils/JWT.js +++ /dev/null @@ -1,15 +0,0 @@ -import jwt from "jsonwebtoken"; -const generateToken = (payload, secret, expiresIn) => { - const token = jwt.sign(payload, secret, { - algorithm: "HS256", - expiresIn: expiresIn, - }); - return token; -}; -const verifyToken = (token, secret) => { - return jwt.verify(token, secret); -}; -export const jwtHelpers = { - generateToken, - verifyToken, -}; diff --git a/dist/app/utils/app_error.js b/dist/app/utils/app_error.js deleted file mode 100644 index fd82542..0000000 --- a/dist/app/utils/app_error.js +++ /dev/null @@ -1,13 +0,0 @@ -export class AppError extends Error { - statusCode; - constructor(message, statusCode, stack = '') { - super(message); - this.statusCode = statusCode; - if (stack) { - this.stack = stack; - } - else { - Error.captureStackTrace(this, this.constructor); - } - } -} diff --git a/dist/app/utils/catch_async.js b/dist/app/utils/catch_async.js deleted file mode 100644 index 15940c5..0000000 --- a/dist/app/utils/catch_async.js +++ /dev/null @@ -1,11 +0,0 @@ -const catchAsync = (fn) => { - return async (req, res, next) => { - try { - await fn(req, res, next); - } - catch (error) { - next(error); - } - }; -}; -export default catchAsync; diff --git a/dist/app/utils/cloudinary.js b/dist/app/utils/cloudinary.js deleted file mode 100644 index 62ec6e1..0000000 --- a/dist/app/utils/cloudinary.js +++ /dev/null @@ -1,23 +0,0 @@ -import { v2 as cloudinary } from 'cloudinary'; -import fs from 'fs'; -import { configs } from '../configs/index.js'; -// Configuration -cloudinary.config({ - cloud_name: configs.cloudinary.cloud_name, - api_key: configs.cloudinary.cloud_api_key, - api_secret: configs.cloudinary.cloud_api_secret, -}); -const uploadCloud = async (file) => { - return new Promise((resolve, reject) => { - cloudinary.uploader.upload(file.path, (error, result) => { - fs.unlinkSync(file.path); - if (error) { - reject(error); - } - else { - resolve(result); - } - }); - }); -}; -export default uploadCloud; diff --git a/dist/app/utils/mail_sender.js b/dist/app/utils/mail_sender.js deleted file mode 100644 index c8b321f..0000000 --- a/dist/app/utils/mail_sender.js +++ /dev/null @@ -1,113 +0,0 @@ -import nodemailer from 'nodemailer'; -import { configs } from '../configs/index.js'; -const transporter = nodemailer.createTransport({ - host: "smtp.gmail.com", - port: 465, - secure: true, // true for 465, false for other ports - auth: { - user: configs.email.app_email, - pass: configs.email.app_password, - }, -}); -// ✅ Email Sender Function -const sendMail = async (payload) => { - const info = await transporter.sendMail({ - from: 'info@digitalcreditai.com', - to: payload.to, - subject: payload.subject, - text: payload.textBody, - html: ` - - - - - Welcome Email - - - - - -
-
-

- Hi ${payload?.name || ""}, -

- - ${payload?.htmlBody} - -
- Quick Launch - -

The Support Team

-

Quick Launch

-
-
-

- This is an automated message — please do not reply to this email. -
- If you need assistance, feel free to contact our support team. -

- Thank you for choosing us! -

- -
-
- © 2026 to {{year}} Quick Launch. All rights reserved. -
-
- - - - - `, - }); - return info; -}; -export default sendMail; diff --git a/dist/app/utils/manage_response.js b/dist/app/utils/manage_response.js deleted file mode 100644 index d33865a..0000000 --- a/dist/app/utils/manage_response.js +++ /dev/null @@ -1,9 +0,0 @@ -const manageResponse = (res, payload) => { - res.status(payload.statusCode).json({ - success: payload.success, - message: payload.message, - data: payload.data || undefined || null, - meta: payload.meta || undefined || null - }); -}; -export default manageResponse; diff --git a/dist/app/utils/otpGenerator.js b/dist/app/utils/otpGenerator.js deleted file mode 100644 index 842096d..0000000 --- a/dist/app/utils/otpGenerator.js +++ /dev/null @@ -1,23 +0,0 @@ -export const otpGenerator = () => { - const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const lower = "abcdefghijklmnopqrstuvwxyz"; - const numbers = "0123456789"; - const symbols = "@#$%&*!?"; - const allChars = upper + lower + numbers + symbols; - let otp = ""; - // Ensure at least one character from each set - otp += upper[Math.floor(Math.random() * upper.length)]; - otp += lower[Math.floor(Math.random() * lower.length)]; - otp += numbers[Math.floor(Math.random() * numbers.length)]; - otp += symbols[Math.floor(Math.random() * symbols.length)]; - // Fill the rest randomly - for (let i = otp.length; i < 6; i++) { - otp += allChars[Math.floor(Math.random() * allChars.length)]; - } - // Shuffle to remove predictable order - otp = otp - .split("") - .sort(() => Math.random() - 0.5) - .join(""); - return otp; -}; diff --git a/dist/app/utils/pagination_helper.js b/dist/app/utils/pagination_helper.js deleted file mode 100644 index 63a8a8f..0000000 --- a/dist/app/utils/pagination_helper.js +++ /dev/null @@ -1,15 +0,0 @@ -const paginationHelper = (options) => { - const page = Number(options?.page) || 1; - const limit = Number(options?.limit) || 10; - const skip = (page - 1) * limit; - const sortBy = options?.sortBy || "createdAt"; - const sortOrder = options?.sortOrder || "desc"; - return { - page, - limit, - skip, - sortBy, - sortOrder - }; -}; -export default paginationHelper; diff --git a/dist/routes.js b/dist/routes.js deleted file mode 100644 index 5185c65..0000000 --- a/dist/routes.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Router } from "express"; -import accountRouter from "./app/modules/account/account.route.js"; -import orderRoute from "./app/modules/order/order.route.js"; -import planRoute from "./app/modules/plan/plan.route.js"; -import profileRoute from "./app/modules/profile/profile.route.js"; -import supportRoute from "./app/modules/support/support.route.js"; -const appRouter = Router(); -const moduleRoutes = [ - { path: "/order", route: orderRoute }, - { path: "/support", route: supportRoute }, - { path: "/plan", route: planRoute }, - { path: "/profile", route: profileRoute }, - { path: "/auth", route: accountRouter }, -]; -moduleRoutes.forEach((route) => appRouter.use(route.path, route.route)); -export default appRouter; diff --git a/dist/server.js b/dist/server.js deleted file mode 100644 index f1110e5..0000000 --- a/dist/server.js +++ /dev/null @@ -1,19 +0,0 @@ -import app from "./app.js"; -import { configs } from "./app/configs/index.js"; -import { prisma } from "./app/lib/prisma.js"; -import "./app/queues/worker.js"; -async function main() { - try { - app.listen(configs.port, async () => { - await prisma.$connect(); - console.log(`Server is running on port ${configs.port}`); - }); - } - catch (error) { - console.error("Error starting server:", error); - } -} -main().catch((error) => { - console.error("Error in main function:", error); - process.exit(1); -}); diff --git a/dist/swaggerOptions.js b/dist/swaggerOptions.js deleted file mode 100644 index 9915a0f..0000000 --- a/dist/swaggerOptions.js +++ /dev/null @@ -1,48 +0,0 @@ -import { fileURLToPath } from "node:url"; -import path from "path"; -import { configs } from "./app/configs/index.js"; -import { accountSwaggerDocs } from "./app/modules/account/account.swagger.js"; -import { orderSwaggerDocs } from "./app/modules/order/order.swagger.js"; -import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js"; -import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js"; -import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js"; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -export const swaggerOptions = { - definition: { - openapi: "3.0.0", - info: { - title: "API Doc - Build with exp-node-server", - version: "1.0.0", - description: "Express + Prisma API with auto-generated Swagger docs", - }, - paths: { - ...accountSwaggerDocs, - ...planSwaggerDocs, - ...orderSwaggerDocs, - ...profileSwaggerDocs, - ...supportSwaggerDocs, - }, - servers: configs.env === "production" - ? [{ url: "https://quicklunch-server.onrender.com" }, { url: "http://localhost:5000" }] - : [{ url: "http://localhost:5000" }, { url: "https://quicklunch-server.onrender.com" }], - components: { - securitySchemes: { - AuthorizationToken: { - type: "apiKey", - in: "header", - name: "Authorization", - description: "Put your accessToken here ", - }, - }, - }, - security: [ - { - AuthorizationToken: [], - }, - ], - }, - apis: [ - path.join(__dirname, configs.env === "production" ? "./**/*.js" : "./**/*.ts"), - ], -}; -- 2.52.0 From f224ff6bf0c1624d6d6e5b3ea3a2eb7382bad554 Mon Sep 17 00:00:00 2001 From: sharafat Date: Wed, 17 Jun 2026 22:01:03 +0600 Subject: [PATCH 07/11] Add api: Users --- src/app/modules/order/order.service.ts | 3 +- src/app/modules/profile/profile.service.ts | 1 - src/app/modules/users/users.service.ts | 48 ++++++++++++---------- src/app/modules/users/users.swagger.ts | 12 +++--- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/app/modules/order/order.service.ts b/src/app/modules/order/order.service.ts index e554f37..864b9ed 100644 --- a/src/app/modules/order/order.service.ts +++ b/src/app/modules/order/order.service.ts @@ -130,7 +130,7 @@ const get_single_order_from_db = async (req: Request) => { const create_order_into_db = async (req: Request) => { const payload = req?.body; - console.log(payload); + payload.status = "INITIATED"; payload.paymentType = "COD"; @@ -153,7 +153,6 @@ const create_order_into_db = async (req: Request) => { const update_order_into_db = async (req: Request) => { // define your own login here const user = req.user; - console.log(user); if (user?.role !== "ADMIN") { throw new AppError("You are not authorized to perform this action", 403); } diff --git a/src/app/modules/profile/profile.service.ts b/src/app/modules/profile/profile.service.ts index 5aaf758..b93e02d 100644 --- a/src/app/modules/profile/profile.service.ts +++ b/src/app/modules/profile/profile.service.ts @@ -7,7 +7,6 @@ const update_profile_into_db = async (req: Request) => { const user = req?.user as JwtPayloadType; const payload = req?.body; const file = req?.file; - console.log(payload); // check file and upload to cloud if (file) { const cloudRes = await uploadCloud(file); diff --git a/src/app/modules/users/users.service.ts b/src/app/modules/users/users.service.ts index c45dd3e..8404cb8 100644 --- a/src/app/modules/users/users.service.ts +++ b/src/app/modules/users/users.service.ts @@ -1,58 +1,63 @@ - import { Request } from "express"; import { prisma } from "../../lib/prisma.js"; import paginationHelper from "../../utils/pagination_helper.js"; const get_all_users_from_db = async (req: Request) => { - const {page,skip,limit}=paginationHelper(req.query); - + const { page, skip, limit } = paginationHelper(req.query); + const search = req.query.search as string; + const andCondition = {} as any; + if (search) { + andCondition.shopName = { + contains: search, + mode: "insensitive", + }; + } // define your own login here const result = await prisma.profile.findMany({ - take:limit, + take: limit, skip, - select:{ - account:{ - select:{ - isSubscribe:true, - email:true, - - } + where: andCondition, + select: { + account: { + select: { + isSubscribe: true, + email: true, + }, }, - shopName:true, - id:true, - status:true - - } + shopName: true, + id: true, + status: true, + }, }); const usersCount = await prisma.profile.count(); - return{ result,usersCount,page,limit,skip}; + return { result, usersCount, page, limit, skip }; }; const get_single_users_from_db = async (req: Request) => { // define your own login here const { id } = req.params as { id: string }; - const result = await prisma.account.findUnique({where:{id}}); + const result = await prisma.profile.findUnique({ where: { id } }); return result; }; const create_users_into_db = async (req: Request) => { // define your own login here - const result = await prisma.account.create({data:req.body}); + const result = await prisma.account.create({ data: req.body }); return result; }; const update_users_into_db = async (req: Request) => { // define your own login here const { id } = req.params as { id: string }; - const result = await prisma.account.update({where:{id},data:req.body}); + const result = await prisma.account.update({ where: { id }, data: req.body }); return result; }; const delete_users_from_db = async (req: Request) => { // define your own login here const { id } = req.params as { id: string }; - const result = await prisma.account.delete({where:{id}}); + const result = await prisma.account.delete({ where: { id } }); return result; }; @@ -63,4 +68,3 @@ export const users_service = { update_users_into_db, delete_users_from_db, }; - \ No newline at end of file diff --git a/src/app/modules/users/users.swagger.ts b/src/app/modules/users/users.swagger.ts index a951986..4672e12 100644 --- a/src/app/modules/users/users.swagger.ts +++ b/src/app/modules/users/users.swagger.ts @@ -1,5 +1,4 @@ - - export const usersSwaggerDocs = { +export const usersSwaggerDocs = { "/api/users": { post: { tags: ["users"], @@ -35,6 +34,12 @@ required: false, schema: { type: "number" }, }, + { + name: "search", + in: "query", + required: false, + schema: { type: "string" }, + }, ], responses: { 200: { description: "users fetched successfully" }, @@ -105,6 +110,3 @@ }, }, }; - - - \ No newline at end of file -- 2.52.0 From 3ce71be9299cbcd92a9e3932296957c2075d81f4 Mon Sep 17 00:00:00 2001 From: sharafat Date: Wed, 17 Jun 2026 23:09:05 +0600 Subject: [PATCH 08/11] Bug/db-update:Fixed the db update related issues and also update the filter system --- src/app/modules/order/order.service.ts | 68 +++++++---------------- src/app/modules/order/order.swagger.ts | 2 +- src/app/modules/order/order.validation.ts | 2 +- 3 files changed, 22 insertions(+), 50 deletions(-) diff --git a/src/app/modules/order/order.service.ts b/src/app/modules/order/order.service.ts index 864b9ed..8be34f1 100644 --- a/src/app/modules/order/order.service.ts +++ b/src/app/modules/order/order.service.ts @@ -19,54 +19,30 @@ const get_all_order_from_db = async (req: Request) => { const status = (req.query.status as string) || undefined; const { page, limit, skip, sortBy, sortOrder } = paginationHelper(req.query); - const andCondition = [] as any[]; + const andCondition = {} as any; if (search) { - andCondition.push({ - OR: [ - { - productName: { - contains: search, - mode: "insensitive", - }, - }, - ], - }); + andCondition.productName = { + contains: search, + mode: "insensitive", + }; } if (customerName) { - andCondition.push({ - OR: [ - { - customerName: { - contains: customerName, - mode: "insensitive", - }, - }, - ], - }); + andCondition.customerName = { + contains: customerName, + mode: "insensitive", + }; } if (productName) { - andCondition.push({ - OR: [ - { - productName: { - contains: productName, - mode: "insensitive", - }, - }, - ], - }); + andCondition.productName = { + contains: productName, + mode: "insensitive", + }; } if (status) { - andCondition.push({ - OR: [ - { - status: { - contains: status, - mode: "insensitive", - }, - }, - ], - }); + andCondition.status = { + contains: status, + mode: "insensitive", + }; } // for date filter @@ -82,17 +58,13 @@ const get_all_order_from_db = async (req: Request) => { dateFilter.lte = end; } if (Object.keys(dateFilter).length > 0) { - andCondition.push({ - createdAt: dateFilter, - }); + andCondition.createdAt = dateFilter; } const getAllOrders = await prisma.order.findMany({ take: limit, skip, - where: { - AND: andCondition, - }, + where: andCondition, select: { id: true, customerName: true, @@ -130,7 +102,7 @@ const get_single_order_from_db = async (req: Request) => { const create_order_into_db = async (req: Request) => { const payload = req?.body; - + payload.status = "INITIATED"; payload.paymentType = "COD"; diff --git a/src/app/modules/order/order.swagger.ts b/src/app/modules/order/order.swagger.ts index f4d705c..b281705 100644 --- a/src/app/modules/order/order.swagger.ts +++ b/src/app/modules/order/order.swagger.ts @@ -121,7 +121,7 @@ export const orderSwaggerDocs = { patch: { tags: ["order"], summary: "Update order -(Admin route)", - description: "", + description: "The status can be updated to any of the following values : INITIATED,CONFIRMED,ONGOING,DELIVERED,CANCELLED", parameters: [ { name: "id", diff --git a/src/app/modules/order/order.validation.ts b/src/app/modules/order/order.validation.ts index e3a08aa..9b23609 100644 --- a/src/app/modules/order/order.validation.ts +++ b/src/app/modules/order/order.validation.ts @@ -13,7 +13,7 @@ const create_order = z.object({ customerNote: z.string().optional() }); const update_order = z.object({ - status: z.string().optional() + status: z.enum(["INITIATED","CONFIRMED","ONGOING","DELIVERED","CANCELLED"]).optional() }); export const order_validations = { -- 2.52.0 From 9188d7a7e58b5d23602a17e3c31abe247795ffe2 Mon Sep 17 00:00:00 2001 From: sharafat Date: Thu, 18 Jun 2026 10:20:10 +0600 Subject: [PATCH 09/11] Add the readme.md file and fix the bug issue in db updating --- readme.md | 153 +++++++++++++++++++----------------------------------- 1 file changed, 53 insertions(+), 100 deletions(-) diff --git a/readme.md b/readme.md index 9a821dc..a503c1c 100644 --- a/readme.md +++ b/readme.md @@ -1,77 +1,74 @@ -# ⚡ Express Server CLI +# QuickLaunch Server -[![npm version](https://img.shields.io/npm/v/exp-node-server.svg)](https://www.npmjs.com/package/exp-node-server) -[![npm downloads](https://img.shields.io/npm/dw/exp-node-server.svg)](https://www.npmjs.com/package/exp-node-server) -[![npm total downloads](https://img.shields.io/npm/dt/exp-node-server.svg)](https://www.npmjs.com/package/exp-node-server) -[![Made with TypeScript](https://img.shields.io/badge/Made%20with-TypeScript-blue.svg)](https://www.typescriptlang.org/) -[![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/) +### This server is a nodejs server with express framework. It provides a REST API for quicklunch app. It is written in typescript and uses prisma for database.It is deployed on docker and is managed by docker compose. ---- +### Features -## 🚀 Overview +- Authentication +- Authorization +- Database Management +- REST API +- Testing +- Deployment -A powerful `Express + TypeScript CLI` that instantly generates scalable `backend` modules with `Mongoose `/ `Prisma`, `Zod` `validation`, and `Swagger` documentation. +### Technologies -This tool helps developers quickly scaffold `clean`, `modular` `Express` APIs with minimal setup. +- Nodejs +- Express +- Typescript +- Prisma +- Docker +- Docker Compose +- Bullmq + -Nodemailer -## ✨ Features +### Deployment -- ⚡ Generate complete `Express` + `TypeScript` modules -- 🧩 Built-in `Mongoose` / `Prisma` support -- 📘 Adds Swagger documentation automatically -- 📘 Automatic `Swagger` documentation -- 🔐 `Zod` validation ready -- 🏗️ `Modular` clean architecture -- 🚀 One command project setup -- 🔄 Add modules anytime -- 📦 Zero boilerplate setup +- Docker +- Docker Compose -## 📦 Quick Start +### Authentication -Run directly using npx (recommended): +- JWT -```Bash -npx exp-node-server -c my-api -``` +### Installation -This will: +- git clone git@codelab.techzaa.tech:summer2026/quicklanch-server.git +- cd quicklunch-server +- npm install +- npm run dev -- Create an Express starter project -- Install dependencies -- Prepare the project for development +### Environment variables are stored in .env file. They are: +Set up or add the following environment variables in .env file to run the server. You will copy and paste them from the .env.example file by adding Database URL,APP USER EMAIL, APP PASSWORD, CLOUD NAME, CLOUD API KEY, CLOUD API SECRET and REDIS URL : +- PORT = 5000 +- DATABASE_URL +-ACCESS_TOKEN=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68 +- ACCESS_EXPIRES=24h +- RESET_SECRET=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68 +- RESET_EXPIRES=5m +- VERIFIED_TOKEN=8b8ba26578276a8bf9d0599f8c0ec0d2d69e0aec9171e989a314c36db0b330a23fd0365a6c9b1059406856046e28dc0e13c9d6a165e2936e6614aa2d1862af68 +- FRONT_END_URL=http://localhost:5173/ +- APP_USER_EMAIL +- APP_PASSWORD +- CLOUD_NAME +- CLOUD_API_KEY +- CLOUD_API_SECRET +- REDIS_URL -## 🧩 Generate a Module +### API Documentation -Inside your project run: +- API documentation is available at http://localhost:5000/api-docs + +### API Creating +If you need to create an new api you will only run simple command the command is ```bash -npx express-server-cli -g + npx exp-node-server -g API_NAME (Your api name or folder name) ``` -Example: `npx express-server-cli -g order` - -Output: - -```Bash -✔ order.interface.ts created -✔ order.schema.ts created -✔ order.validation.ts created -✔ order.route.ts created -✔ order.controller.ts created -✔ order.service.ts created -✔ order.swagger.ts created - -🔗 Route registered in routes.ts -📘 Swagger docs registered - +### API Structure ``` - -## 📁 Generated Module Structure - -Each module follows a clean structure: - -```Bash -src/app/modules// + src/app/modules// ├── .interface.ts ├── .schema.ts ├── .validation.ts @@ -79,48 +76,4 @@ src/app/modules// ├── .controller.ts ├── .service.ts └── .swagger.ts -``` - -## ⚙️ Run the Project - -```bash -npm run dev -``` - -Swagger docs available at: - -```bash -http://localhost:5000/docs -``` - -## 🧠 Tech Stack - -- Express.js — Backend framework -- TypeScript — Strongly typed JavaScript -- Mongoose — MongoDB ODM -- Prisma — PostgreSQL ORM -- Zod — Runtime schema validation -- JWT — Authentication -- Swagger — API documentation - -## 👨‍💻 Author - -### Abumahid - -GitHub -https://github.com/dev-abumahid - -npm -https://www.npmjs.com/~dev_abumahid - -Portfolio -https://abumahid.me - -LinkedIn -https://linkedin.com/in/md-abu-mahid-islam - -## ⭐ Support - -If you find this project helpful, consider giving it a ⭐ on `GitHub`. - -It helps the project grow and reach more developers. + ``` \ No newline at end of file -- 2.52.0 From aaea7f99c4ede3a94e6885a0f25cc8374819db05 Mon Sep 17 00:00:00 2001 From: abumahid Date: Sat, 23 May 2026 20:12:09 +0600 Subject: [PATCH 10/11] update --- src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.ts b/src/app.ts index 4a328f8..2683b6a 100644 --- a/src/app.ts +++ b/src/app.ts @@ -15,7 +15,7 @@ app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); // middleware app.use(cors({ - origin: ["http://localhost:5173"], + origin: ["http://localhost:5173","https://quick-launch-techzaa.vercel.app"], methods: ["GET", "POST", "PATCH", "DELETE", "PUT"], credentials: true })) -- 2.52.0 From 8298f27194ceaf1425fd2270267fee64b57747b2 Mon Sep 17 00:00:00 2001 From: abumahid Date: Thu, 18 Jun 2026 11:03:41 +0600 Subject: [PATCH 11/11] fix: missing environment variable type and variable validation --- src/app/configs/index.ts | 48 +++++++++++++++++++++++++--------------- src/routes.ts | 4 ++-- src/swaggerOptions.ts | 4 ++-- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/app/configs/index.ts b/src/app/configs/index.ts index 1553fd2..796307d 100644 --- a/src/app/configs/index.ts +++ b/src/app/configs/index.ts @@ -1,27 +1,39 @@ import "dotenv/config"; +function getEnv(key: string): string { + const value = process.env[key]; + + if (!value) { + throw new Error(`Missing required environment variable: ${key}`); + } + + return value; +} + export const configs = { - port: process.env.PORT, - env: process.env.NODE_ENV, - db_url: process.env.DATABASE_URL, + port: getEnv("PORT"), + env: getEnv("NODE_ENV"), + db_url: getEnv("DATABASE_URL"), + jwt: { - access_token: process.env.ACCESS_TOKEN, - refresh_token: process.env.REFRESH_TOKEN, - access_expires: process.env.ACCESS_EXPIRES, - refresh_expires: process.env.REFRESH_EXPIRES, - reset_secret: process.env.RESET_SECRET, - reset_expires: process.env.RESET_EXPIRES, - front_end_url: process.env.FRONT_END_URL, - verified_token: process.env.VERIFIED_TOKEN, + access_token: getEnv("ACCESS_TOKEN"), + access_expires: getEnv("ACCESS_EXPIRES"), + reset_secret: getEnv("RESET_SECRET"), + reset_expires: getEnv("RESET_EXPIRES"), + front_end_url: getEnv("FRONT_END_URL"), + verified_token: getEnv("VERIFIED_TOKEN"), }, + email: { - app_email: process.env.APP_USER_EMAIL, - app_password: process.env.APP_PASSWORD, + app_email: getEnv("APP_USER_EMAIL"), + app_password: getEnv("APP_PASSWORD"), }, + cloudinary: { - cloud_name: process.env.CLOUD_NAME, - cloud_api_key: process.env.CLOUD_API_KEY, - cloud_api_secret: process.env.CLOUD_API_SECRET, + cloud_name: getEnv("CLOUD_NAME"), + cloud_api_key: getEnv("CLOUD_API_KEY"), + cloud_api_secret: getEnv("CLOUD_API_SECRET"), }, - redis_url: process.env.REDIS_URL, -}; + + redis_url: getEnv("REDIS_URL"), +}; \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index e873c17..c26296d 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -4,8 +4,8 @@ import orderRoute from "./app/modules/order/order.route.js"; import planRoute from "./app/modules/plan/plan.route.js"; import profileRoute from "./app/modules/profile/profile.route.js"; import supportRoute from "./app/modules/support/support.route.js"; -import templateRoute from "./app/modules/template/template.route"; -import usersRoute from "./app/modules/users/users.route"; +import templateRoute from "./app/modules/template/template.route.js"; +import usersRoute from "./app/modules/users/users.route.js"; const appRouter = Router(); diff --git a/src/swaggerOptions.ts b/src/swaggerOptions.ts index 34fd8ba..088c662 100644 --- a/src/swaggerOptions.ts +++ b/src/swaggerOptions.ts @@ -6,8 +6,8 @@ import { orderSwaggerDocs } from "./app/modules/order/order.swagger.js"; import { planSwaggerDocs } from "./app/modules/plan/plan.swagger.js"; import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger.js"; import { supportSwaggerDocs } from "./app/modules/support/support.swagger.js"; -import { templateSwaggerDocs } from "./app/modules/template/template.swagger"; -import { usersSwaggerDocs } from "./app/modules/users/users.swagger"; +import { templateSwaggerDocs } from "./app/modules/template/template.swagger.js"; +import { usersSwaggerDocs } from "./app/modules/users/users.swagger.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -- 2.52.0