♻️ 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
+80
View File
@@ -0,0 +1,80 @@
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,
};
+12
View File
@@ -0,0 +1,12 @@
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;
+100
View File
@@ -0,0 +1,100 @@
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,
};
+109
View File
@@ -0,0 +1,109 @@
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" },
},
},
},
};
+28
View File
@@ -0,0 +1,28 @@
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,
};