Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
"dependencies": {
"bcryptjs": "^2.4.3",
"cloudinary": "^2.8.0",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-validator": "^7.0.1",
"helmet": "^8.1.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.3",
"morgan": "^1.10.1",
Expand All @@ -35,6 +37,7 @@
},
"devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/cookie-parser": "^1.4.10",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.5",
Expand Down
106 changes: 63 additions & 43 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,74 @@
import dotenv from 'dotenv';
dotenv.config();

import express, { Application } from 'express';
import express from 'express';
import cors from 'cors';
import morgan from "morgan";
import { errorHandler } from './middlewares/errorMiddleware';

import authRoutes from './routes/authRoutes';
import notificationRoutes from './routes/notificationRoutes';
import workshopRoutes from './routes/workshopRoutes';
import teamRoutes from './routes/teamRoutes';
import roleRoutes from './routes/roleRoutes';
import workshopProjectRoutes from './routes/workshopProjectRoutes';
import workshopTaskRoutes, { taskRouter, userTaskRouter, teamTaskRouter } from './routes/workshopTaskRoutes';
import auditRoutes from './routes/auditRoutes';
import permissionRoutes from './routes/permissionRoutes';
import chatRoutes from './routes/chatRoutes';
import activityRoutes from './routes/activityRoutes';
import morgan from 'morgan';
import helmet from 'helmet';
import cookieParser from 'cookie-parser';
import passport from 'passport';

const app: Application = express();
import Database from './config/db.config';
import { Container } from '@di/types';
import { env } from './config/env';

import createAuthRoutes from './modules/auth/routes/authRoutes';
import createNotificationRoutes from './modules/notification/routes/notificationRoutes';
import createWorkshopRoutes from './modules/workshop/routes/workshopRoutes';
import createTeamRoutes from './modules/team/routes/teamRoutes';
import createRoleRoutes from './modules/access-control/routes/roleRoutes';
import createWorkshopProjectRoutes from './modules/project/routes/workshopProjectRoutes';
import createWorkshopTaskRoutes, {
createTaskRouter,
createUserTaskRouter,
createTeamTaskRouter
} from './modules/task/routes/workshopTaskRoutes';
import createAuditRoutes from './modules/audit/routes/auditRoutes';
import createPermissionRoutes from './modules/access-control/routes/permissionRoutes';
import createChatRoutes from './modules/chat/routes/chatRoutes';
import createActivityRoutes from './modules/audit/routes/activityRoutes';
import createInviteRoutes from './modules/invitation/routes/inviteRoutes';

import { errorHandler, injectContainer } from '@middlewares';
import { configurePassport } from './config/passport';
import { API_PREFIX, MODULE_BASE } from '@constants';

export const createApp = (container: Container) => {
const app = express();

Database.getInstance();

app.use(passport.initialize());
app.use(helmet());
app.use(injectContainer(container));
app.use(cookieParser());
app.use(cors({
origin: env.FRONTEND_URL,
credentials: true
}));

app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(morgan("dev"));
app.use(passport.initialize());
configurePassport(container);

app.use('/api/auth', authRoutes);
app.use('/api/notifications', notificationRoutes);
app.use(`${API_PREFIX}${MODULE_BASE.AUTH}`, createAuthRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.NOTIFICATIONS}`, createNotificationRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.WORKSHOPS}`, createWorkshopRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.TEAMS}`, createTeamRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.ROLES}`, createRoleRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.PROJECTS}`, createWorkshopProjectRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.PROJECT_TASKS}`, createWorkshopTaskRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.AUDIT}`, createAuditRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.PERMISSION_CHECK}`, createPermissionRoutes(container));

app.use('/api/workshops', workshopRoutes);
app.use('/api/workshops/:workshopId/teams', teamRoutes);
app.use('/api/workshops/:workshopId/roles', roleRoutes);
app.use('/api/workshops/:workshopId/projects', workshopProjectRoutes);
app.use('/api/workshops/:workshopId/projects/:projectId/tasks', workshopTaskRoutes);
app.use('/api/workshops/:workshopId/audit', auditRoutes);
app.use('/api/workshops/:workshopId/permissions', permissionRoutes);
app.use('/api/workshop-tasks', taskRouter);
app.use('/api/users', userTaskRouter);
app.use('/api/teams', teamTaskRouter);
app.use(`${API_PREFIX}${MODULE_BASE.TASKS}`, createTaskRouter(container));
app.use(`${API_PREFIX}${MODULE_BASE.USER_TASKS}`, createUserTaskRouter(container));
app.use(`${API_PREFIX}${MODULE_BASE.TEAM_TASKS}`, createTeamTaskRouter(container));

app.use('/api/chat', chatRoutes);
app.use('/api', activityRoutes);
app.use(`${API_PREFIX}${MODULE_BASE.CHAT}`, createChatRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.INVITES}`, createInviteRoutes(container));
app.use(`${API_PREFIX}${MODULE_BASE.ACTIVITY}`, createActivityRoutes(container));

app.use(errorHandler);
app.use(errorHandler);

export default app;
return app;
}
18 changes: 18 additions & 0 deletions backend/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createDIContainer } from "./di";
import { createApp } from "./app";
import { createServer } from "http";
import { env } from "./config/env";

export const bootstrap = async () => {
const httpServer = createServer();

const container = createDIContainer(httpServer);

const app = createApp(container);
httpServer.on('request', app);

httpServer.listen(env.PORT, () => {
console.log(`Server started on port ${env.PORT}`);
console.log(`Environment: ${env.NODE_ENV}`);
});
};
10 changes: 10 additions & 0 deletions backend/src/config/cloudinary.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { v2 as cloudinary } from 'cloudinary';
import { env } from './env';

cloudinary.config({
cloud_name: env.CLOUDINARY_CLOUD_NAME,
api_key: env.CLOUDINARY_API_KEY,
api_secret: env.CLOUDINARY_API_SECRET
});

export default cloudinary;
2 changes: 1 addition & 1 deletion backend/src/config/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const connectDatabase = async (): Promise<void> => {

await mongoose.connect(mongoUri);

console.log('MongoDB connected successfully');
console.log('MongoDB connected successfully');

mongoose.connection.on('error', (error) => {
console.error('MongoDB connection error:', error);
Expand Down
29 changes: 29 additions & 0 deletions backend/src/config/db.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import mongoose from 'mongoose';
import { env } from './env';

class Database {
private static instance: Database;

private constructor() {
this.connect();
}

public static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}

private async connect() {
try {
await mongoose.connect(env.MONGODB_URI);
console.log('MongoDB connected successfully');
} catch (error) {
console.error('MongoDB connection error:', error);
process.exit(1);
}
}
}

export default Database;
2 changes: 2 additions & 0 deletions backend/src/config/env.init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import dotenv from 'dotenv';
dotenv.config();
13 changes: 13 additions & 0 deletions backend/src/config/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import dotenv from 'dotenv';
dotenv.config();

export const env = {
PORT: process.env.PORT || 5001,
MONGODB_URI: process.env.MONGODB_URI || 'mongodb://localhost:27017/teamup',
FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:3000',
JWT_SECRET: process.env.JWT_SECRET || 'secret',
CLOUDINARY_CLOUD_NAME: process.env.CLOUDINARY_CLOUD_NAME,
CLOUDINARY_API_KEY: process.env.CLOUDINARY_API_KEY,
CLOUDINARY_API_SECRET: process.env.CLOUDINARY_API_SECRET,
NODE_ENV: process.env.NODE_ENV || 'development'
};
7 changes: 3 additions & 4 deletions backend/src/config/passport.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { Strategy as GitHubStrategy } from 'passport-github2';
import { AuthService } from '../services/AuthService';

const authService = new AuthService();
import { Container } from '../di/types';

export const isStrategyEnabled = (strategy: string): boolean => {
switch (strategy) {
Expand All @@ -22,7 +20,8 @@ export const isStrategyEnabled = (strategy: string): boolean => {
}
};

export const configurePassport = () => {
export const configurePassport = (container: Container) => {
const authService = container.authSrv;

if (isStrategyEnabled('google')) {
console.log('Initializing Google Strategy...');
Expand Down
Loading