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/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/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/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/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 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/app/modules/order/order.service.ts b/src/app/modules/order/order.service.ts index 1285906..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,16 +58,20 @@ 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, + productQuantity: true, + productPrice: true, + status: true, + createdAt: true, }, orderBy: { [sortBy as string]: sortOrder, @@ -122,7 +102,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"; @@ -145,7 +125,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/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 = { 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/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/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/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" }, + }, + }, + }, +}; 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..4b4be06 --- /dev/null +++ b/src/app/modules/template/template.service.ts @@ -0,0 +1,143 @@ +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 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 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 as { id: string }; + 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 as { id: string }; + 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..9fcd93b --- /dev/null +++ b/src/app/modules/template/template.swagger.ts @@ -0,0 +1,197 @@ +export const templateSwaggerDocs = { + "/api/template": { + post: { + tags: ["template"], + summary: "Create new template", + description: "", + requestBody: { + required: true, + content: { + "application/json": { + 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 + }, + }, + }, + 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..0243549 --- /dev/null +++ b/src/app/modules/template/template.validation.ts @@ -0,0 +1,87 @@ +import { z } from "zod"; + +// 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 = { + create_template, + update_template, +}; 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..8404cb8 --- /dev/null +++ b/src/app/modules/users/users.service.ts @@ -0,0 +1,70 @@ +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 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, + skip, + where: andCondition, + select: { + account: { + select: { + isSubscribe: true, + email: true, + }, + }, + shopName: true, + id: true, + status: true, + }, + }); + const usersCount = await prisma.profile.count(); + 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.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 }); + 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, +}; diff --git a/src/app/modules/users/users.swagger.ts b/src/app/modules/users/users.swagger.ts new file mode 100644 index 0000000..4672e12 --- /dev/null +++ b/src/app/modules/users/users.swagger.ts @@ -0,0 +1,112 @@ +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" }, + }, + { + name: "search", + in: "query", + required: false, + schema: { type: "string" }, + }, + ], + 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" }, + }, + }, + }, +}; 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 a7ac1a2..c26296d 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -4,10 +4,14 @@ 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.js"; +import usersRoute from "./app/modules/users/users.route.js"; const appRouter = Router(); const moduleRoutes = [ + { path: "/users", route: usersRoute }, + { 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..088c662 100644 --- a/src/swaggerOptions.ts +++ b/src/swaggerOptions.ts @@ -6,6 +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.js"; +import { usersSwaggerDocs } from "./app/modules/users/users.swagger.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -24,6 +26,8 @@ export const swaggerOptions = { ...orderSwaggerDocs, ...profileSwaggerDocs, ...supportSwaggerDocs, + ...templateSwaggerDocs, + ...usersSwaggerDocs, }, servers: configs.env === "production"