Initialized Project with default middlewares and helpers, connected to Atlas Instance and created Swagger Setup. Created necessary DB models and authentication-authorization logic

This commit is contained in:
Shibi Chakkaravarthy
2026-04-15 02:28:35 +05:30
commit 864e5fae65
71 changed files with 8184 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
Executable
+16
View File
@@ -0,0 +1,16 @@
{
"presets": [
[
"@babel/env",
{
"targets": {
"node": "current"
}
}
]
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread"
]
}
+4
View File
@@ -0,0 +1,4 @@
node_modules
.env
.env*
+123
View File
@@ -0,0 +1,123 @@
import { createAccess } from "../models/Access/operations.js";
import { createRole, getAllRoles } from "../models/Role/operations.js";
import {
createDesignation,
getAllDesignations,
} from "../models/Designation/operations.js";
import {
createDepartment,
getAllDepartments,
} from "../models/Department/operations.js";
import { createBranch, getAllBranches } from "../models/Branch/operations.js";
import dayjs from "dayjs";
export const createAccessController = async (req, res) => {
try {
const { user } = res.locals;
const { employee, designation, department, branch, role } = req.body;
const access = await createAccess({
user: employee,
designation,
department,
branch,
role,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: access });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllRolesController = async (req, res) => {
try {
const roles = await getAllRoles();
res.status(200).json({ result: roles });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllDesignationsController = async (req, res) => {
try {
const designations = await getAllDesignations();
res.status(200).json({ result: designations });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllDepartmentsController = async (req, res) => {
try {
const departments = await getAllDepartments();
res.status(200).json({ result: departments });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const getAllBranchesController = async (req, res) => {
try {
const branches = await getAllBranches();
res.status(200).json({ result: branches });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const createRoleController = async (req, res) => {
try {
const { user } = res.locals;
const role = await createRole({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: role });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const createDesignationController = async (req, res) => {
try {
const { user } = res.locals;
const designation = await createDesignation({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: designation });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const createDepartmentController = async (req, res) => {
try {
const { user } = res.locals;
const department = await createDepartment({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: department });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
export const createBranchController = async (req, res) => {
try {
const { user } = res.locals;
const branch = await createBranch({
...req.body,
createdBy: user.id,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: branch });
} catch (error) {
res.status(500).json({ error: error.message });
}
};
View File
+33
View File
@@ -0,0 +1,33 @@
import {
createProfile,
getProfileByQuery,
updateProfile,
} from "../models/Profile/operations.js";
export const createOrEditProfileController = async (req, res, next) => {
try {
const { user } = res.locals;
const profile = await updateProfile(user.id, req.body, {
new: true,
upsert: true,
});
res.status(200).json({ result: profile });
} catch (error) {
console.log("createProfileController Error", error);
next(error);
}
};
export const getProfileController = async (req, res, next) => {
try {
const { user } = res.locals;
const profile = await getProfileByQuery({ userId: user.id });
res.status(200).json({ result: profile });
} catch (error) {
console.log("getProfileController Error", error);
next(error);
}
};
+76
View File
@@ -0,0 +1,76 @@
import { createUser, getUserByQuery } from "../models/User/operations.js";
import bcrypt from "bcrypt";
import dayjs from "dayjs";
import {
getAccessToken,
getRefreshToken,
} from "../middlewares/jwt.middleware.js";
export const createUserController = async (req, res, next) => {
try {
const { id, name, password } = req.body;
const hash = await bcrypt.hash(password, 10);
const userExists = await getUserByQuery({ id });
if (userExists) {
throw { code: 400, message: "User already exists for this id" };
}
const refreshToken = getRefreshToken();
const user = await createUser({
id,
name,
hash: hash,
refreshToken,
createdOn: dayjs().toISOString(),
});
res.status(200).json({ result: user });
} catch (error) {
console.log("createUserController Error", error);
next(error);
}
};
export const loginController = async (req, res, next) => {
try {
const { id, password } = req.body;
const userExists = await getUserByQuery({ id });
if (!userExists) {
throw { code: 404, message: "User not found" };
}
const isPasswordValid = await bcrypt.compare(password, userExists.hash);
if (!isPasswordValid) {
throw { code: 400, message: "Invalid Password" };
}
const accessToken = getAccessToken({ id: userExists._id });
const refreshToken = getRefreshToken();
userExists.refreshToken = refreshToken;
await userExists.save();
res
.status(200)
.json({ result: { accessToken, refreshToken, name: userExists?.name } });
} catch (error) {
console.log("loginController Error", error);
next(error);
}
};
export const renewAccessTokenController = async (req, res, next) => {
try {
const { refreshToken } = req.body;
const userExists = await getUserByQuery({ refreshToken });
if (!userExists) {
throw { code: 404, message: "User not found" };
}
const accessToken = getAccessToken({ id: userExists._id });
res.status(200).json({ result: accessToken });
} catch (error) {
console.log("renewAccessTokenController Error", error);
next(error);
}
};
+1
View File
@@ -0,0 +1 @@
import { User, Access, Profile, Team } from "../models/index.js";
BIN
View File
Binary file not shown.
+241
View File
@@ -0,0 +1,241 @@
import { Designation } from "../models";
export default {
"/admin/access": {
post: {
tags: ["Admin"],
summary: "Create Access for an Employee",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
user: {
type: "string",
required: true,
},
designation: {
type: "array",
required: true,
},
department: {
type: "string",
required: true,
},
role: {
type: "string",
required: true,
},
branch: {
type: "array",
items: {
type: "string",
},
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/branches": {
get: {
tags: ["Admin"],
summary: "Get All Branches",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/designations": {
get: {
tags: ["Admin"],
summary: "Get All Designations",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/departments": {
get: {
tags: ["Admin"],
summary: "Get All Departments",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/roles": {
get: {
tags: ["Admin"],
summary: "Get All Roles",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/branch": {
post: {
tags: ["Admin"],
summary: "Create New Branch",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
pincode: {
type: "string",
required: true,
},
coordinates: {
type: "object",
required: true,
properties: {
latitude: {
type: "number",
required: true,
},
longitude: {
type: "number",
required: true,
},
},
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/designation": {
post: {
tags: ["Admin"],
summary: "Create New Designation",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/department": {
post: {
tags: ["Admin"],
summary: "Create New Department",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/admin/role": {
post: {
tags: ["Admin"],
summary: "Create New Role",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+491
View File
@@ -0,0 +1,491 @@
{
"openapi": "3.0.1",
"info": {
"title": "Attica Server Application v1",
"description": "Version 1 of Attica Server Application API",
"license": {
"name": "MIT",
"url": "https://opensource.org/licenses/MIT"
},
"version": "1.0.0"
},
"servers": [
{
"url": "http://localhost:3000/v0/"
},
{
"url": "https://erp-server.triadkube.com/v0/"
}
],
"security": [
{
"bearerAuth": []
}
],
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
},
"paths": {
"/user/create": {
"post": {
"tags": [
"Auth"
],
"summary": "Create Account for New User",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
},
"id": {
"type": "string",
"required": true
},
"password": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/user/login": {
"post": {
"tags": [
"Auth"
],
"summary": "Login with Employee Id and Password",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"required": true
},
"password": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/user/token/renew": {
"post": {
"tags": [
"Auth"
],
"summary": "Login with Employee Code and Password",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"refreshToken": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/profile": {
"post": {
"tags": [
"Profile"
],
"summary": "Create or Edit Profile New User",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"user": {
"type": "string",
"required": true
},
"mobile": {
"type": "string",
"required": true
},
"address": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
},
"state": {
"type": "string",
"required": true
},
"pincode": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
},
"get": {
"tags": [
"Profile"
],
"summary": "Get Profile for a User",
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/uploads/single/{folder}": {
"post": {
"tags": [
"Uploads"
],
"summary": "Endpoint to handle Single File",
"parameters": [
{
"in": "path",
"name": "folder"
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/access": {
"post": {
"tags": [
"Admin"
],
"summary": "Create Access for an Employee",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"user": {
"type": "string",
"required": true
},
"designation": {
"type": "array",
"required": true
},
"department": {
"type": "string",
"required": true
},
"role": {
"type": "string",
"required": true
},
"branch": {
"type": "array",
"items": {
"type": "string"
},
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/branches": {
"get": {
"tags": [
"Admin"
],
"summary": "Get All Branches",
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/designations": {
"get": {
"tags": [
"Admin"
],
"summary": "Get All Designations",
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/departments": {
"get": {
"tags": [
"Admin"
],
"summary": "Get All Departments",
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/roles": {
"get": {
"tags": [
"Admin"
],
"summary": "Get All Roles",
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/branch": {
"post": {
"tags": [
"Admin"
],
"summary": "Create New Branch",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
},
"address": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
},
"state": {
"type": "string",
"required": true
},
"pincode": {
"type": "string",
"required": true
},
"coordinates": {
"type": "object",
"required": true,
"properties": {
"latitude": {
"type": "number",
"required": true
},
"longitude": {
"type": "number",
"required": true
}
}
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/designation": {
"post": {
"tags": [
"Admin"
],
"summary": "Create New Designation",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/department": {
"post": {
"tags": [
"Admin"
],
"summary": "Create New Department",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
},
"/admin/role": {
"post": {
"tags": [
"Admin"
],
"summary": "Create New Role",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK",
"content": {}
}
}
}
}
}
}
+65
View File
@@ -0,0 +1,65 @@
import path from "path";
import fs from "fs";
import upload from "./upload.js";
import user from "./user.js";
import profile from "./profile.js";
import admin from "./admin.js";
const GENERAL_CONFIG = {
openapi: "3.0.1",
info: {
title: "Attica Server Application v1",
description: "Version 1 of Attica Server Application API",
license: {
name: "MIT",
url: "https://opensource.org/licenses/MIT",
},
version: "1.0.0",
},
servers: [
{
url: "http://localhost:3000/v0/",
},
{
url: "https://erp-server.triadkube.com/v0/",
},
],
security: [
{
bearerAuth: [],
},
],
components: {
securitySchemes: {
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
},
},
};
let paths = {
...user,
...profile,
...upload,
...admin,
};
const getSwaggerDocument = () => {
const swaggerDocument = {
...GENERAL_CONFIG,
paths,
};
const fileContent = JSON.stringify(swaggerDocument, null, 2);
const docPath = path.resolve(path.join(__dirname, "documentation.json"));
const existingContent = fs.readFileSync(docPath, "utf8");
if (existingContent !== fileContent) {
console.log("Swagger documentation updated");
fs.writeFileSync(docPath, fileContent);
}
};
export default getSwaggerDocument;
+60
View File
@@ -0,0 +1,60 @@
export default {
"/profile": {
post: {
tags: ["Profile"],
summary: "Create or Edit Profile New User",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
user: {
type: "string",
required: true,
},
mobile: {
type: "string",
required: true,
},
address: {
type: "string",
required: true,
},
city: {
type: "string",
required: true,
},
state: {
type: "string",
required: true,
},
pincode: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
get: {
tags: ["Profile"],
summary: "Get Profile for a User",
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+36
View File
@@ -0,0 +1,36 @@
export default {
"/uploads/single/{folder}": {
post: {
tags: ["Uploads"],
summary: "Endpoint to handle Single File",
parameters: [
{
in: "path",
name: "folder",
},
],
requestBody: {
required: true,
content: {
"multipart/form-data": {
schema: {
type: "object",
properties: {
file: {
type: "string",
format: "binary",
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
+98
View File
@@ -0,0 +1,98 @@
export default {
"/user/create": {
post: {
tags: ["Auth"],
summary: "Create Account for New User",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
name: {
type: "string",
required: true,
},
id: {
type: "string",
required: true,
},
password: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/user/login": {
post: {
tags: ["Auth"],
summary: "Login with Employee Id and Password",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
id: {
type: "string",
required: true,
},
password: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
"/user/token/renew": {
post: {
tags: ["Auth"],
summary: "Login with Employee Code and Password",
requestBody: {
required: true,
content: {
"application/json": {
schema: {
type: "object",
properties: {
refreshToken: {
type: "string",
required: true,
},
},
},
},
},
},
responses: {
200: {
description: "OK",
content: {},
},
},
},
},
};
View File
View File
+115
View File
@@ -0,0 +1,115 @@
import express from "express";
// import fs from "fs";
import path from "path";
import cors from "cors";
import mongoose from "mongoose";
import dotenv from "dotenv";
import swaggerUi from "swagger-ui-express";
// import WebSocket, { WebSocketServer } from "ws";
// import { bufferDataConverter, verifyToken } from "./helpers";
// import rootHandler from "./event-handlers/root.handler";
import swaggerDoc from "./documentation/documentation.json";
import getSwaggerDocument from "./documentation";
// import socketState from "./state/socketState.js";
import { AdminRoutes, UserRoutes } from "./routes";
dotenv.config();
getSwaggerDocument();
console.log(
"ENV",
process.env.DB_NAME,
process.env.DB_URL,
process.env.DB_USER,
process.env.DB_PASSWORD,
);
mongoose.connect(
`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_URL}/${process.env.DB_NAME}`,
{},
);
const db = mongoose.connection;
db.on("error", (error) => console.error(error));
db.once("open", () =>
console.log("Connected to MongoDB " + process.env.DB_NAME + " database"),
);
const app = express();
app.use(cors());
app.use(express.json());
app.use("/v0/docs", swaggerUi.serve, swaggerUi.setup(swaggerDoc));
app.use("/v0/user", UserRoutes);
app.use("/v0/admin", AdminRoutes);
app.use((err, req, res, next) => {
const statusCode = err.status || 500;
console.log("ACTUAL ERROR", err);
res.status(statusCode).json({
success: false,
error: {
...err,
message: err.message,
},
});
});
app.listen(process.env.PORT || 3000, () => {
console.log(`Server is running on port ${process.env.PORT || 3000}`);
});
// const wss = new WebSocketServer({
// port: 8080,
// });
// wss.on("connection", (ws, request) => {
// const url = new URL(request.url, `http://${request?.headers?.host}`);
// const type = url.searchParams.get("type");
// const id = url.searchParams.get("id");
// const user_token = url.searchParams.get("token");
// const system_token = url.searchParams.get("system_token");
// // Validate token before accepting connection
// const userData = verifyToken(user_token, system_token);
// if (!userData) {
// console.log("Authentication failed: Invalid token");
// ws.close(4001, "Invalid or missing token");
// return;
// }
// // Store authenticated client in state
// const clientData = {
// userId: userData.userId,
// type,
// id,
// authenticated: true,
// userToken: user_token,
// systemToken: system_token,
// connectedAt: new Date(),
// };
// socketState.addClient(ws, clientData);
// console.log("Client connected:", { type, id, userId: userData.userId });
// ws.on("message", (message, request) => {
// const data = bufferDataConverter(message);
// console.log("message", data, typeof data);
// // Pass ws reference to rootHandler so it can access client data from socketState
// rootHandler({ data, ws });
// });
// // Clean up when client disconnects
// ws.on("close", () => {
// transactionRoomState.leaveAll(ws);
// socketState.removeClient(ws);
// console.log("Client disconnected:", { type, id });
// });
// });
//
// console.log("WebSocket server running on ws://localhost:8080");
View File
+70
View File
@@ -0,0 +1,70 @@
import jwt from "jsonwebtoken";
import crypto from "node:crypto";
import User from "../models/User/model.js";
import Access from "../models/Access/model.js";
export const getAccessToken = (payload) => {
return jwt.sign(payload, process.env.ECT_KEY, {
algorithm: "HS256",
expiresIn: "7m",
});
};
export const getRefreshToken = () => {
return crypto.randomBytes(32).toString("hex");
};
export const authorize = (requiredModule, requiredPermission) => {
return async (req, res, next) => {
try {
const authHeader = req.headers.authorization;
if (!authHeader) {
throw { code: 401, message: "Bearer Token Missing" };
}
const token = authHeader.replace("Bearer ", "");
const verifiedPayload = jwt.verify(token, process.env.ECT_KEY || "");
// 1. Check if User exists
const userExists = await User.exists({ _id: verifiedPayload.id });
if (!userExists) {
throw { code: 404, message: "User not found" };
}
// 2. Fetch Access and Populate Role
// Assuming Access model has a 'user' field and a 'role' field
const access = await Access.findOne({
user: verifiedPayload.id,
}).populate("role");
console.log("access", access?.role?.modules);
if (!access || !access.role) {
throw { code: 403, message: "No role assigned to this user" };
}
// 3. Verify Permissions
const hasPermission = access?.role?.modules?.some(
(mod) =>
(mod.module === requiredModule &&
mod.permission === requiredPermission) ||
(requiredModule === "generic" && requiredPermission === "generic"),
);
if (!hasPermission) {
throw {
code: 403,
message: `Insufficient permissions for ${requiredModule} (${requiredPermission})`,
};
}
// Success
res.locals.user = verifiedPayload;
next();
} catch (error) {
console.error("AUTH_ERROR", error);
res.status(error.code || 401).json(error);
}
};
};
BIN
View File
Binary file not shown.
+41
View File
@@ -0,0 +1,41 @@
import { model, Schema, Types } from "mongoose";
import user from "../../documentation/user";
const schema = new Schema({
user: {
type: Types.ObjectId,
required: true,
ref: "user",
},
designation: {
type: Types.ObjectId,
required: true,
ref: "designation",
},
department: {
type: Types.ObjectId,
required: true,
ref: "department",
},
role: {
type: Types.ObjectId,
required: true,
ref: "role",
},
branch: {
type: [Types.ObjectId],
required: true,
ref: "branch",
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
createdOn: {
type: Date,
required: true,
},
});
export default model("access", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createAccess = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getAccessById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getAccessByQuery = async (query) => {
return await Model.findOne(query);
};
// Read (Get all)
export const getAllAccesss = async () => {
return await Model.find();
};
// Update
export const updateAccess = async (id, data, options) => {
return await Model.findByIdAndUpdate(id, data, { ...options, new: true });
};
// Aggregate
export const aggregateAccess = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("activity", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createActivity = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getActivityById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getActivityByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllActivitys = async () => {
return await Model.find();
};
// Update
export const updateActivity = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateActivity = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("assignment", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createAssignment = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getAssignmentById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getAssignmentByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllAssignments = async () => {
return await Model.find();
};
// Update
export const updateAssignment = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateAssignment = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+10
View File
@@ -0,0 +1,10 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
createdOn: {
type: Date,
required: true
}
});
export default model("branch", schema);
+55
View File
@@ -0,0 +1,55 @@
import { model, Schema, Types } from "mongoose";
const coordinatesSchema = new Schema({
latitude: {
type: Number,
required: true,
},
longitude: {
type: Number,
required: true,
},
});
const schema = new Schema({
name: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
pincode: {
type: String,
required: true,
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
createdOn: {
type: Date,
required: true,
},
coordinates: {
type: coordinatesSchema,
required: true,
},
type: {
type: String,
required: true,
enum: ["HQ", "Branch", "Warehouse", "BackOffice"],
},
});
export default model("branch", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createBranch = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getBranchById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getBranchByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllBranches = async () => {
return await Model.find();
};
// Update
export const updateBranch = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateBranch = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+19
View File
@@ -0,0 +1,19 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
name: {
type: String,
required: true,
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
createdOn: {
type: Date,
required: true,
},
});
export default model("department", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createDepartment = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getDepartmentById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getDepartmentByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllDepartments = async () => {
return await Model.find();
};
// Update
export const updateDepartment = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateDepartment = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+19
View File
@@ -0,0 +1,19 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
name: {
type: String,
required: true,
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
createdOn: {
type: Date,
required: true,
},
});
export default model("designation", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createDesignation = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getDesignationById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getDesignationByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllDesignations = async () => {
return await Model.find();
};
// Update
export const updateDesignation = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateDesignation = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("expense", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createExpense = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getExpenseById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getExpenseByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllExpenses = async () => {
return await Model.find();
};
// Update
export const updateExpense = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateExpense = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("inventory", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createInventory = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getInventoryById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getInventoryByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllInventorys = async () => {
return await Model.find();
};
// Update
export const updateInventory = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateInventory = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("inventorylog", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createInventoryLog = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getInventoryLogById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getInventoryLogByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllInventoryLogs = async () => {
return await Model.find();
};
// Update
export const updateInventoryLog = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateInventoryLog = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("invoice", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createInvoice = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getInvoiceById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getInvoiceByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllInvoices = async () => {
return await Model.find();
};
// Update
export const updateInvoice = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateInvoice = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("location", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createLocation = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getLocationById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getLocationByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllLocations = async () => {
return await Model.find();
};
// Update
export const updateLocation = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateLocation = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("partner", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createPartner = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getPartnerById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getPartnerByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllPartners = async () => {
return await Model.find();
};
// Update
export const updatePartner = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregatePartner = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+48
View File
@@ -0,0 +1,48 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
sku: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
buyingPrice: {
type: Number,
required: true,
},
sellingPrice: {
type: Number,
required: true,
},
gst: {
type: Number,
required: true,
},
stock: {
type: Number,
required: true,
},
createdOn: {
type: Date,
required: true,
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
vendors: {
type: [Types.ObjectId],
required: true,
ref: "vendor",
},
});
export default model("product", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createProduct = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getProductById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getProductByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllProducts = async () => {
return await Model.find();
};
// Update
export const updateProduct = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateProduct = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+34
View File
@@ -0,0 +1,34 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
mobile: {
type: String,
required: true,
},
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
pincode: {
type: String,
required: true,
},
isActive: {
type: Boolean,
default: true,
},
user: {
type: Types.ObjectId,
required: true,
},
});
export default model("profile", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createProfile = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getProfileById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getProfileByQuery = async (query) => {
return await Model.findOne(query);
};
// Read (Get all)
export const getAllProfiles = async () => {
return await Model.find();
};
// Update
export const updateProfile = async (id, data, options) => {
return await Model.findByIdAndUpdate(id, data, options);
};
// Aggregate
export const aggregateProfile = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+63
View File
@@ -0,0 +1,63 @@
import { model, Schema, Types } from "mongoose";
const moduleSchema = new Schema({
module: {
type: String,
required: true,
enum: [
"branch",
"role",
"designation",
"department",
"user",
"profile",
"access",
"team",
"task",
"target",
"salary",
"vendor",
"expense",
"product",
"invoice",
"partner",
"activity",
"location",
"assignment",
"inventory",
"inventoryLog",
],
},
permission: {
type: String,
required: true,
enum: ["read", "write", "authorize", "delete"],
},
});
const schema = new Schema({
name: {
type: String,
required: true,
},
modules: {
type: [moduleSchema],
required: true,
},
keys: {
type: [String],
required: true,
enum: ["accounts", "admin", "sales", "field", "hr", "logistics"],
},
createdBy: {
type: Types.ObjectId,
required: true,
ref: "user",
},
createdOn: {
type: Date,
required: true,
},
});
export default model("role", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createRole = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getRoleById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getRoleByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllRoles = async () => {
return await Model.find();
};
// Update
export const updateRole = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateRole = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("salary", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createSalary = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getSalaryById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getSalaryByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllSalarys = async () => {
return await Model.find();
};
// Update
export const updateSalary = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateSalary = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("target", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createTarget = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getTargetById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getTargetByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllTargets = async () => {
return await Model.find();
};
// Update
export const updateTarget = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateTarget = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("task", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createTask = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getTaskById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getTaskByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllTasks = async () => {
return await Model.find();
};
// Update
export const updateTask = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateTask = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("team", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createTeam = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getTeamById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getTeamByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllTeams = async () => {
return await Model.find();
};
// Update
export const updateTeam = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateTeam = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+30
View File
@@ -0,0 +1,30 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({
name: {
type: String,
required: true,
},
id: {
type: String,
required: true,
},
hash: {
type: String,
required: true,
},
refreshToken: {
type: String,
required: true,
},
isFirstTime: {
type: Boolean,
default: true,
},
createdOn: {
type: Date,
required: true,
},
});
export default model("user", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createUser = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getUserById = async (id) => {
return await Model.findById(id);
};
//Read (Get by query)
export const getUserByQuery = async (query) => {
return await Model.findOne(query);
};
// Read (Get all)
export const getAllUsers = async () => {
return await Model.find();
};
// Update
export const updateUser = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateUser = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+5
View File
@@ -0,0 +1,5 @@
import { model, Schema, Types } from "mongoose";
const schema = new Schema({});
export default model("vendor", schema);
+31
View File
@@ -0,0 +1,31 @@
import Model from "./model.js";
// Create
export const createVendor = async (data) => {
return await Model.create(data);
};
// Read (Get by ID)
export const getVendorById = async (id) => {
return await Model.findById(id);
};
// Read (Get by Query)
export const getVendorByQuery = async (query) => {
return await Model.findOne(query);
}
// Read (Get all)
export const getAllVendors = async () => {
return await Model.find();
};
// Update
export const updateVendor = async (id, data) => {
return await Model.findByIdAndUpdate(id, data, { new: true });
};
// Aggregate
export const aggregateVendor = async (pipeline) => {
return await Model.aggregate(pipeline);
};
+21
View File
@@ -0,0 +1,21 @@
export { default as User } from "./User/model";
export { default as Profile } from "./Profile/model";
export { default as Access } from "./Access/model";
export { default as Team } from "./Team/model";
export { default as Task } from "./Task/model";
export { default as Target } from "./Target/model";
export { default as Branch } from "./Branch/model";
export { default as Salary } from "./Salary/model";
export { default as Vendor } from "./Vendor/model";
export { default as Expense } from "./Expense/model";
export { default as Product } from "./Product/model";
export { default as Invoice } from "./Invoice/model";
export { default as Partner } from "./Partner/model";
export { default as Activity } from "./Activity/model";
export { default as Location } from "./Location/model";
export { default as Assignment } from "./Assignment/model";
export { default as Department } from "./Department/model";
export { default as Designation } from "./Designation/model";
export { default as Inventory } from "./Inventory/model";
export { default as InventoryLog } from "./InventoryLog/model";
export { default as Role } from "./Role/model";
+5587
View File
File diff suppressed because it is too large Load Diff
+35
View File
@@ -0,0 +1,35 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "nodemon --exec babel-node --inspect index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"bcrypt": "^6.0.0",
"body-parser": "^2.2.2",
"cors": "^2.8.6",
"dayjs": "^1.11.20",
"dotenv": "^17.4.1",
"express": "^5.2.1",
"haversine": "^1.1.1",
"jsonwebtoken": "^9.0.3",
"mongoose": "^9.4.1",
"swagger-ui-express": "^5.0.1",
"ws": "^8.20.0"
},
"devDependencies": {
"@babel/cli": "^7.28.6",
"@babel/core": "^7.29.0",
"@babel/node": "^7.29.0",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-proposal-object-rest-spread": "^7.20.7",
"@babel/preset-env": "^7.29.2",
"nodemon": "^3.1.14"
}
}
+43
View File
@@ -0,0 +1,43 @@
import { Router } from "express";
import { authorize } from "../middlewares/jwt.middleware";
import {
createAccessController,
getAllBranchesController,
getAllDesignationsController,
getAllDepartmentsController,
getAllRolesController,
createBranchController,
createDepartmentController,
createDesignationController,
createRoleController,
} from "../controllers/admin.controller";
const router = new Router();
router.post("/access", authorize("access", "write"), createAccessController);
router.get("/branches", authorize("branch", "read"), getAllBranchesController);
router.get(
"/designations",
authorize("designation", "read"),
getAllDesignationsController,
);
router.get(
"/departments",
authorize("department", "read"),
getAllDepartmentsController,
);
router.get("/roles", authorize("role", "read"), getAllRolesController);
router.post("/branch", authorize("branch", "write"), createBranchController);
router.post(
"/department",
authorize("department", "write"),
createDepartmentController,
);
router.post(
"/designation",
authorize("designation", "write"),
createDesignationController,
);
router.post("/role", authorize("role", "write"), createRoleController);
export default router;
+3
View File
@@ -0,0 +1,3 @@
export { default as UserRoutes } from "./user.route";
export { default as ProfileRoutes } from "./profile.route";
export { default as AdminRoutes } from "./admin.route";
+17
View File
@@ -0,0 +1,17 @@
import { Router } from "express";
import {
createOrEditProfileController,
getProfileController,
} from "../controllers/profile.controller";
import { authorize } from "../middlewares/jwt.middleware";
const router = new Router();
router.post(
"/",
authorize("generic", "generic"),
createOrEditProfileController,
);
router.get("/", authorize("generic", "generic"), getProfileController);
export default router;
+14
View File
@@ -0,0 +1,14 @@
import { Router } from "express";
import {
createUserController,
loginController,
renewAccessTokenController,
} from "../controllers/user.controller";
const router = new Router();
router.post("/create", createUserController);
router.post("/login", loginController);
router.post("/token/renew", renewAccessTokenController);
export default router;