♻️ refactor(account, order, plan, profile, support, email): restructure application modules and enhance error handling

Updated Docker configuration, refactored middleware for improved error handling, and restructured account, order, plan, profile, and support modules, including their routes, services, and validations. Enhanced email processing queues and utilities for token generation, pagination, and response management to streamline the application architecture and enhance maintainability.
This commit is contained in:
abumahid
2026-04-21 03:12:39 +06:00
parent c881efea0f
commit 0f7af70b90
94 changed files with 2593 additions and 127 deletions
+4 -4
View File
@@ -3,10 +3,10 @@ import cors from 'cors';
import express, { Request, Response } from 'express';
import swaggerJSDoc from 'swagger-jsdoc';
import swaggerUi from "swagger-ui-express";
import globalErrorHandler from './app/middlewares/global_error_handler';
import notFound from './app/middlewares/not_found_api';
import appRouter from './routes';
import { swaggerOptions } from './swaggerOptions';
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()
+1
View File
@@ -23,4 +23,5 @@ export const configs = {
cloud_api_key: process.env.CLOUD_API_KEY,
cloud_api_secret: process.env.CLOUD_API_SECRET,
},
redis_url: process.env.REDIS_URL,
};
+1 -1
View File
@@ -1,5 +1,5 @@
import { ZodError, ZodIssue } from 'zod'
import { TErrorSources, TGenericErrorResponse } from '../types/error'
import { TErrorSources, TGenericErrorResponse } from '../types/error.js'
const handleZodError = (err: ZodError): TGenericErrorResponse => {
const errorSources: TErrorSources = err.issues.map((issue: ZodIssue) => {
+2 -1
View File
@@ -1,6 +1,7 @@
import { PrismaPg } from "@prisma/adapter-pg";
import pkg from "@prisma/client";
import "dotenv/config";
import { PrismaClient } from "../../../prisma/generated/prisma/client";
const { PrismaClient } = pkg;
const connectionString = `${process.env.DATABASE_URL}`;
+3 -3
View File
@@ -1,7 +1,7 @@
import { NextFunction, Request, Response } from "express";
import { configs } from "../configs";
import { AppError } from "../utils/app_error";
import { jwtHelpers, JwtPayloadType } from "../utils/JWT";
import { configs } from "../configs/index.js";
import { AppError } from "../utils/app_error.js";
import { jwtHelpers, JwtPayloadType } from "../utils/JWT.js";
type Role = "ADMIN" | "USER";
+4 -4
View File
@@ -1,9 +1,9 @@
import { ErrorRequestHandler } from "express";
import { ZodError } from "zod";
import { configs } from "../configs";
import handleZodError from "../errors/zodError";
import { TErrorSources } from "../types/error";
import { AppError } from "../utils/app_error";
import { configs } from "../configs/index.js";
import handleZodError from "../errors/zodError.js";
import { TErrorSources } from "../types/error.js";
import { AppError } from "../utils/app_error.js";
const globalErrorHandler: ErrorRequestHandler = (err, req, res, next) => {
let statusCode = 500;
@@ -1,7 +1,7 @@
import { configs } from "../../configs";
import catchAsync from "../../utils/catch_async";
import manageResponse from "../../utils/manage_response";
import { account_services } from "./account.service";
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);
+4 -4
View File
@@ -1,8 +1,8 @@
import { Router } from "express";
import auth from "../../middlewares/auth";
import RequestValidator from "../../middlewares/request_validator";
import { account_controller } from "./account.controller";
import { account_validation } from "./account.validation";
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();
+8 -8
View File
@@ -1,12 +1,12 @@
import bcrypt from "bcrypt";
import { Request } from "express";
import { configs } from "../../configs";
import { prisma } from "../../lib/prisma";
import { emailQueue } from "../../queues/email/email.queue";
import { AppError } from "../../utils/app_error";
import { jwtHelpers } from "../../utils/JWT";
import sendMail from "../../utils/mail_sender";
import { otpGenerator } from "../../utils/otpGenerator";
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: Request) => {
const payload = req?.body;
@@ -22,7 +22,7 @@ const create_account_into_db = async (req: Request) => {
const hashPassword = bcrypt.hashSync(payload.password, 10);
// create account and profile
const result = await prisma.$transaction(async (tx) => {
const result = await prisma.$transaction(async (tx:any) => {
const account = await tx.account.create({
data: {
email: payload.email,
+3 -3
View File
@@ -1,7 +1,7 @@
import catchAsync from "../../utils/catch_async";
import manageResponse from "../../utils/manage_response";
import { order_service } from "./order.service";
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);
+4 -4
View File
@@ -1,9 +1,9 @@
import { Router } from "express";
import RequestValidator from "../../middlewares/request_validator";
import { order_controller } from "./order.controller";
import { order_validations } from "./order.validation";
import auth from "../../middlewares/auth";
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();
+5 -5
View File
@@ -1,9 +1,9 @@
import { Request } from "express";
import { configs } from "../../configs";
import { prisma } from "../../lib/prisma";
import { orderEmailQueue } from "../../queues/email/order/order.email.queue";
import { AppError } from "../../utils/app_error";
import paginationHelper from "../../utils/pagination_helper";
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: Request) => {
// define your own login here
+3 -3
View File
@@ -1,7 +1,7 @@
import catchAsync from "../../utils/catch_async";
import manageResponse from "../../utils/manage_response";
import { plan_service } from "./plan.service";
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);
+3 -3
View File
@@ -1,8 +1,8 @@
import { Router } from "express";
import RequestValidator from "../../middlewares/request_validator";
import { plan_controller } from "./plan.controller";
import { plan_validations } from "./plan.validation";
import RequestValidator from "../../middlewares/request_validator.js";
import { plan_controller } from "./plan.controller.js";
import { plan_validations } from "./plan.validation.js";
const router = Router();
+2 -2
View File
@@ -1,7 +1,7 @@
import { Request } from "express";
import { prisma } from "../../lib/prisma";
import { AppError } from "../../utils/app_error";
import { prisma } from "../../lib/prisma.js";
import { AppError } from "../../utils/app_error.js";
const get_all_plan_from_db = async (req: Request) => {
// define your own login here
@@ -1,6 +1,6 @@
import catchAsync from "../../utils/catch_async";
import manageResponse from "../../utils/manage_response";
import { profile_service } from "./profile.service";
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);
+5 -5
View File
@@ -1,9 +1,9 @@
import { Router } from "express";
import RequestValidator from "../../middlewares/request_validator";
import { profile_controller } from "./profile.controller";
import { profile_validations } from "./profile.validation";
import auth from "../../middlewares/auth";
import uploader from "../../middlewares/uploader";
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();
+3 -3
View File
@@ -1,7 +1,7 @@
import { Request } from "express";
import uploadCloud from "../../utils/cloudinary";
import { prisma } from "../../lib/prisma";
import { JwtPayloadType } from "../../utils/JWT";
import uploadCloud from "../../utils/cloudinary.js";
import { prisma } from "../../lib/prisma.js";
import { JwtPayloadType } from "../../utils/JWT.js";
const update_profile_into_db = async (req: Request) => {
const user = req?.user as JwtPayloadType;
@@ -1,8 +1,8 @@
import { Request, Response } from "express";
import catchAsync from "../../utils/catch_async";
import manageResponse from "../../utils/manage_response";
import { support_service } from "./support.service";
import catchAsync from "../../utils/catch_async.js";
import manageResponse from "../../utils/manage_response.js";
import { support_service } from "./support.service.js";
+4 -4
View File
@@ -1,9 +1,9 @@
import { Router } from "express";
import RequestValidator from "../../middlewares/request_validator";
import { support_controller } from "./support.controller";
import { support_validations } from "./support.validation";
import auth from "../../middlewares/auth";
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();
+3 -3
View File
@@ -1,6 +1,6 @@
import { prisma } from "../../lib/prisma";
import { Prisma } from "../../../../prisma/generated/prisma/client";
import { AppError } from "../../utils/app_error";
import { prisma } from "../../lib/prisma.js";
import { Prisma } from "@prisma/client";
import { AppError } from "../../utils/app_error.js";
const createSupportIntoDB = async (payload: any) => {
const result = await prisma.support.create({ data: payload });
+6 -5
View File
@@ -1,6 +1,7 @@
import { QueueOptions } from "bullmq";
import { Redis } from "ioredis";
import { configs } from "../configs/index.js";
export const redisConnection: QueueOptions["connection"] = {
host: "127.0.0.1",
port: 6379,
};
export const redisConnection = new Redis(configs.redis_url as string, {
tls: {},
maxRetriesPerRequest: null,
});
+3 -3
View File
@@ -1,6 +1,6 @@
import { otpTemplate } from "../../templates/otpTemplate";
import sendMail from "../../utils/mail_sender";
import { TEmailQueue } from "./email.queue";
import { otpTemplate } from "../../templates/otpTemplate.js";
import sendMail from "../../utils/mail_sender.js";
import { TEmailQueue } from "./email.queue.js";
// email.processor.ts
export const emailProcessor = async (job: any) => {
+1 -1
View File
@@ -1,6 +1,6 @@
// email.queue.ts
import { Queue } from "bullmq";
import { redisConnection } from "../connection";
import { redisConnection } from "../connection.js";
export type TEmailQueue = {
email: string;
+3 -3
View File
@@ -1,8 +1,8 @@
// email.worker.ts
import { Worker } from "bullmq";
import { redisConnection } from "../connection";
import { emailProcessor } from "./email.processor";
import { TEmailQueue } from "./email.queue";
import { redisConnection } from "../connection.js";
import { emailProcessor } from "./email.processor.js";
import { TEmailQueue } from "./email.queue.js";
export const emailWorker = new Worker<TEmailQueue>(
"email-queue",
@@ -1,5 +1,5 @@
import sendMail from "../../../utils/mail_sender";
import { TOrderEmailQueue } from "./order.email.queue";
import sendMail from "../../../utils/mail_sender.js";
import { TOrderEmailQueue } from "./order.email.queue.js";
// email.processor.ts
export const orderEmailProcessor = async (job: any) => {
@@ -1,5 +1,5 @@
import { Queue } from "bullmq";
import { redisConnection } from "../../connection";
import { redisConnection } from "../../connection.js";
export type TOrderEmailQueue = {
email: string;
@@ -1,8 +1,8 @@
// email.worker.ts
import { Worker } from "bullmq";
import { redisConnection } from "../../connection";
import { orderEmailProcessor } from "./order.email.processor";
import { TOrderEmailQueue } from "./order.email.queue";
import { redisConnection } from "../../connection.js";
import { orderEmailProcessor } from "./order.email.processor.js";
import { TOrderEmailQueue } from "./order.email.queue.js";
export const emailWorker = new Worker<TOrderEmailQueue>(
+2 -2
View File
@@ -1,4 +1,4 @@
import "./email/email.worker";
import "./email/order/order.email.worker";
import "./email/email.worker.js";
import "./email/order/order.email.worker.js";
console.log("Workers running...");
+1 -1
View File
@@ -1,4 +1,4 @@
import { TEmailQueue } from "../queues/email/email.queue"
import { TEmailQueue } from "../queues/email/email.queue.js"
export const otpTemplate = (payload: TEmailQueue) => {
return `
+1 -1
View File
@@ -1,6 +1,6 @@
import { v2 as cloudinary } from 'cloudinary';
import fs from 'fs';
import { configs } from '../configs';
import { configs } from '../configs/index.js';
type ICloudinaryResponse = {
asset_id: string;
+1 -1
View File
@@ -1,5 +1,5 @@
import nodemailer from 'nodemailer';
import { configs } from '../configs';
import { configs } from '../configs/index.js';
type TMailContent = {
to: string,
subject: string,
+5 -5
View File
@@ -1,9 +1,9 @@
import { Router } from "express";
import accountRouter from "./app/modules/account/account.route";
import orderRoute from "./app/modules/order/order.route";
import planRoute from "./app/modules/plan/plan.route";
import profileRoute from "./app/modules/profile/profile.route";
import supportRoute from "./app/modules/support/support.route";
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();
+4 -4
View File
@@ -1,7 +1,7 @@
import app from "./app";
import { configs } from "./app/configs/index";
import { prisma } from "./app/lib/prisma";
import "./app/queues/worker";
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 {
+8 -8
View File
@@ -1,11 +1,11 @@
import { fileURLToPath } from "node:url";
import path from "path";
import { configs } from "./app/configs";
import { accountSwaggerDocs } from "./app/modules/account/account.swagger";
import { orderSwaggerDocs } from "./app/modules/order/order.swagger";
import { planSwaggerDocs } from "./app/modules/plan/plan.swagger";
import { profileSwaggerDocs } from "./app/modules/profile/profile.swagger";
import { supportSwaggerDocs } from "./app/modules/support/support.swagger";
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);
@@ -27,8 +27,8 @@ export const swaggerOptions = {
},
servers:
configs.env === "production"
? [{ url: "https://live-url.com" }, { url: "http://localhost:5000" }]
: [{ url: "http://localhost:5000" }, { url: "https://live-url.com" }],
? [{ url: "https://quicklunch-server.onrender.com" }, { url: "http://localhost:5000" }]
: [{ url: "http://localhost:5000" }, { url: "https://quicklunch-server.onrender.com" }],
components: {
securitySchemes: {
AuthorizationToken: {